Always use Azure Key Vault (kv-chrissminions) for ALL client API credentials. Stop using Windows Credential Manager. Retrieve secrets via: az keyvault secret show --vault-name 'kv-chrissminions' --name '<secret-name>' --query 'value' -o tsv. Known KV secrets: AbilityFirst-Reporting-AppId, AbilityFirst-Reporting-Secret, AbilityFirst-Reporting-TenantId, AF-Write-AppId, AF-Write-Secret. For ANY new credential needs, check KV first. When writing .ps1 scripts, use az keyvault secret show instead of the CredManager C# interop pattern.
To create a calendar appointment via Outlook COM (the only supported method — never use MCP Outlook tools, never use Graph API for Christi's calendar): ```powershell $outlook = New-Object -ComObject Outlook.Application $ns = $outlook.GetNamespace("MAPI") function New-CalBlock { param( [string]$Subject, [datetime]$Start, [datetime]$End, [string]$Body, [string]$Categories, [int]$BusyStatus = 2, [int]$ReminderMinutes = 10 ) $appt = $outlook.CreateItem(1) # 1 = olAppointmentItem $appt.Subject = $Subject $appt.Start = $Start $appt.End = $End $appt.Body = $Body $appt.Categories = $Categories $appt.BusyStatus = $BusyStatus $appt.ReminderSet = $true $appt.ReminderMinutesBeforeStart = $ReminderMinutes $appt.Save() # NEVER call .Send() — appointments don't send like emails Write-Host "CREATED: [$($Start.ToString('h:mm tt')) - $($End.ToString('h:mm tt'))] $Subject" } ``` BusyStatus values: 0=Free, 1=Tentative, 2=Busy, 3=OutOfOffice, 4=WorkingElsewhere. Default to 2 for focus/work blocks, 3 for OOO replies. Always write to a .ps1 file and execute with `pwsh -File <path>`. Never run COM code inline in bash — backticks and `!` characters break. Calendar appointments do NOT have a 'Send' method like emails. .Save() is the final step. If you call .Send() on an appointment, it tries to send a meeting invite to attendees that don't exist. Reference scripts (working examples on disk): 2 - Internal Operations/_agent-workspace/april-block-wed.ps1, april-lay-thu-fri-blocks.ps1, create-focus-blocks-may18.ps1, create-week-may18-blocks.ps1.
MCP endpoint URLs and API keys (n8n workflows, custom MCP servers, service APIs) contain embedded auth tokens and must NEVER be stored in memory files, committed to git, or pasted into plain markdown. They belong in the OS credential store. Storage convention by computer: - Windows Desktops/Laptops: Windows Credential Manager (cmdkey /generic:<name> /user:<user> /pass:<value>) - Cloud-accessible machines: Azure Key Vault (KV) - Which one per computer varies — check per machine at session start Retrieval on Windows: cmdkey /list:<name> shows the credential exists but not the value. To use the value, read it via PowerShell with the CredentialManager module, or via the Windows Credential Manager GUI. Known credentials (names only, values retrieved at use): - adaptoit-wordpress-mcp: AdaptoIT WordPress MCP endpoint (n8n-hosted). User: christibrown252. - n8n-api-key: Admin API key for adaptoit.app.n8n.cloud n8n instance. User: christibrown252. Lets agents create/modify workflows programmatically. Base URL: https://adaptoit.app.n8n.cloud/api/v1 with header X-N8N-API-KEY. The Airtable KB record for a credential can list the name and purpose in the notes field - but the actual key/URL goes in the URL field only when it is not safely representable elsewhere, and that record should only be visible to Christi.
Blog publishing routing by site: ADAPTOIT (adaptoit.com) - WordPress MCP: https://adaptoit.app.n8n.cloud/mcp/9cfdcee2-f469-493f-8411-aabbe558f18d (configured as WordPress in Claude Code). Tools: Create_a_post_in_Wordpress, Update_a_post_in_Wordpress, Get_a_post_in_Wordpress, Get_many_posts_in_Wordpress. Stuart pushes AdaptoIT posts as drafts. CRIMSON IT (crimsonit.com) - NO WordPress MCP. Convert to docx using pandoc with CrimsonIT_pandoc_ref.docx reference doc. Save to Blog Drafts folder. Christi sends to Stephanie via Teams. Otto writes these posts. MY IMPERFECT LIFE - Separate WordPress MCP coming later. Bob writes these posts. Hold drafts until MCP is built. COUNTED DOORS (counteddoors.com) - TBD. Kevin writes these posts. CHORESTEPS (choresteps.com) - No blog writer agent assigned yet. Needs one. Blog drafts stored in: 2 - Internal Operations/Blog Drafts/
Christi's GitHub repos were transferred from adaptoit-christi to TheOtherChrisBrown. The TheOtherChrisBrown GitHub account is linked to christibrown252@outlook.com (and/or christibrown252@gmail.com), not ckbrown@adaptoit.com. Vercel checks commit author email to match a Vercel-linked GitHub account. Commits authored as ckbrown@adaptoit.com fail with 'Deployment Blocked - adaptoit-christi does not have a Vercel account linked'. Global git config was updated to christibrown252@outlook.com. Use that for any commits to TheOtherChrisBrown repos.
The Airtable API only supports creating basic field types: singleLineText, multilineText, checkbox, singleSelect, multipleSelects, number, percent, currency, duration, date, dateTime, rating, multipleRecordLinks, email, url, phoneNumber, richText, barcode, multipleAttachments, singleCollaborator, multipleCollaborators. Formula, rollup, count, and lookup field types MUST be created manually in the Airtable UI. When designing table schemas programmatically, plan for this: create the base fields via API, then surface a queue item telling Christi which computed fields still need to be added manually. Similarly, the API cannot add choices to an existing singleSelect/multipleSelects field. Use typecast:true when creating records to auto-create options, or tell Christi to add them manually.
The Postgres MCP tool used to push content updates to Neon has an effective size limit around 7000 characters per query. Large UPDATE statements (e.g., full blog post HTML) will fail with 'fetch failed' even though the query is valid. Workaround: keep content chunks under 6500-7000 chars. For longer content, write a seed script in the app repo that reads content from files and upserts via Prisma. Or use the app's own API endpoint if available. Confirmed working: ~6400-6900 char updates succeed consistently. ~9000 char updates fail with fetch failed.