Thnkrr: Swappable Suppliers, the Build Plan

9 October 2026. A step-by-step plan for an AI coding agent (Claude Opus 5.5 in Claude Code). It builds what PROVIDER-SWAP-RESEARCH-2026-10-09.md recommends. Nothing starts until the founder and CTO tick Gate 0.

Read the research file first. Read PRODUCTION-PLAN-2026-10-09.md second: this plan is designed to run interleaved with it, reuses its items where they overlap, and names every overlap so the two never fight.


0. Rules for the agent

  1. Stop at every gate. Report in plain words: what was built, what was tested (paste the test output as it is, failures included), what is left. Never act on production.
  2. Everything is code, in pull requests. Work in worktrees off dev/pilot, branch feat/provider-swap-<phase>, one PR per phase into dev/pilot. Never PR out of main. Never merge the demo/mock-ui branch. Never git stash bare; use a WIP commit.
  3. Adapters, never forks. Every supplier sits behind the existing interface or a new one in src/lib/ or the owning module. The default implementation is always the one that works with no supplier at all (log it, send it to a person, do nothing).
  4. Production refuses the wrong thing. Any setting that could send student data to an unapproved company fails at startup in production, as MODERATION_PROVIDER=anthropic already does. Tests prove the refusal.
  5. Database changes only add. Next migration numbers follow whatever the production plan has used; check drizzle/ before numbering.
  6. Test only what changed, then the whole suite before each PR. No Playwright runs unless a phase says so.
  7. Docs. The decision record for this work is thnkrr-api/docs/29-swappable-suppliers.md (docs/28 belongs to the production plan). Index it in docs/00-overview.md. One grouped Sources section at the end; no inline links. Add decisions to docs/07-decision-log.md as D-80 onward, checking the last used number first.
  8. Plain words in every runbook, log line and alarm: what is wrong for a person using Thnkrr first, the technical cause second.
  9. Rules that stand: every AI model stays on Bedrock or an approved in-account cloud (D-70, Gate 0 decision P3); no student data to a model company's own API; everything in US East unless Gate 0 says otherwise.
  10. The existing single-server deploy files stay in the repo as a working fallback.

1. Gate 0: decisions before any code

The founder decides P1 to P4 and P9; the CTO decides the rest. Recommended choice first.

#DecisionRecommendedAlternative
P1Go ahead with this plan, interleaved with the production planYesAfter the first school
P2Second company for backupsBackblaze B2, US East (Reston)Wasabi; Google Cloud Storage
P3Approved AI fallback cloud (only used if Bedrock's model is unusable)Microsoft Azure AI Foundry, with the abuse-monitoring exemption granted in writing before any useOwn GPU server with vLLM
P4Spare email senderPostmark, 7-day retention requestedZoho ZeptoMail
P5Laptop and CI file stand-in (replacing the unmaintained MinIO)GarageSeaweedFS; R2 free tier in CI only
P6Infrastructure code toolKeep the production plan's CDKOpenTofu
P7Measurements and tracesOpenTelemetry through a collector; CloudWatch as the first backendCloudWatch embedded metric format only
P8SecretsSOPS + age, encrypted files in the repoAmazon Secrets Manager behind a loader
P9Drill cadenceOne drill a quarter; all six at least yearlyTwice a year
P10Registrar and DNSRegistrar separate from hosting; zone in the repo (DNSControl)Everything at Route 53
P11Deploy tool for the any-host pathKamal 2Docker Compose + script
P12Error trackingSentry SDK pointed at a DSN (works with Sentry, GlitchTip, Bugsink)None yet

Humans also do, before Phase 1 (no code):

Gate 0 ticked by: founder (P1 to P4, P9) and CTO (P5 to P8, P10 to P12, and the human steps).


2. Phase 1: the missing seams (agent, about 4 days)

All in thnkrr-api. Each item: what, where, done when.

1.1 Picture-check connector (the seam the docs describe and the code lacks)

1.2 Generic AI connector with an allow-list

1.3 Delivery-network purge adapters

1.4 Visitor address from any edge

1.5 Storage conformance test and the new stand-in

1.6 Mail sender check and spare

1.7 Speech connector: the cloud adapter sits behind the seam

1.8 Secrets encrypted in the repository (P8)

1.9 The providers page and startup manifest

1.10 Off-site backups and the restore drill (P2)

Gate 1 ticked by: CTO, after CI is green on both repos, the conformance run against R2 and the restore drill report are in docs/29, and the agent has shown the providers page.


3. Phase 2: one packaged app, two ways to run it (agent, about 2 days)

2.1 Container image

2.2 Kamal as the any-host deploy path (P11)

2.3 Website publish script

Gate 2 ticked by: CTO, after reading the Kamal dry-run report and the publish script.


4. Phase 3: watching without lock-in (agent, about 2 days)

3.1 OpenTelemetry (P7)

3.2 Errors (P12)

3.3 Outside eyes

Gate 3 ticked by: CTO.


5. Phase 4: addresses and code hosting (agent, about 1 day)

4.1 DNS zone in the repo (P10)

4.2 Mirrors and registries

Gate 4 ticked by: CTO.


6. Phase 5: the supplier register and the first drills (agent + CTO, about 3 days)

5.1 The register

5.2 Six drills, on staging or a throwaway copy, each timed and written down

DrillStepsPass means
Files to R2rclone sync both buckets to R2; set S3_ENDPOINT, keys, S3_PUBLIC_URL to a Cloudflare custom domain; run storage:conformance; upload, approve, view, take down a photoEvery step works; takedown purge via cdn-cloudflare lands within 5 minutes
Email to the spareSet SMTP_URL to the spare; mail:check; sign up a test student; the consent email arrives in a Gmail and an Outlook inbox, not spamBoth inboxes; headers show DKIM pass
AI to the backupmoderation-eval --compare current vs backup model (and, if P3 is approved and exempted, vs the Azure endpoint through openai-compatible); then switch the setting on staging for a dayBackup catches at least as much and wrongly blocks no more; keep-alive green for 24 hours
Delivery network to CloudflarePoint media.thnkrr.com (staging) at Cloudflare in dnsconfig.js; set CDN_PROVIDER=cloudflare, EDGE_IP_HEADER=CF-Connecting-IP; browse, take down, check the visitor address in a consent recordPhotos load; purge lands; address correct
Host to a rented machineKamal deploy of the current image to a non-Amazon VM, pointed at the staging database and R2; run the smoke test; destroy the VMHealthy within the hour; smoke test passes
Database from off-site backuprestore-drill.sh into a managed Postgres at a second company (DigitalOcean or Azure trial); run migrations; point the Kamal host at it; load the feedRow counts match; app answers; time recorded

Each drill gets a one-page runbook in thnkrr-api/runbooks/swap-<thing>.md written from what actually happened, in plain words, with the timing.

Gate 5 ticked by: CTO and founder, after reading the six reports. The drill calendar (P9) goes into the team's shared calendar with the account owner on each.


7. What this plan does not do


8. Settings added or changed, in one place

SettingValuesDefaultPhase
IMAGE_SCREEN_PROVIDERnone, rekognitionnone1.1
IMAGE_SCREEN_OPTOUT_CONFIRMEDtrue required for rekognitionunset1.1
MODERATION_PROVIDERadds openai-compatibleunchanged1.2
AI_BASE_URL, AI_API_KEY, AI_MODEL_IDfor openai-compatibleunset1.2
AI_ALLOWED_HOSTScomma-separated hostsBedrock us-east-1 endpoints1.2
MODERATION_KEEPALIVE_MODEL_IDSprovider-neutral alias of the Bedrock nameunchanged1.2
CDN_PROVIDERnone, cloudfront, cloudflare, bunnyinferred from the CloudFront id1.3
CLOUDFLARE_ZONE_ID, CLOUDFLARE_API_TOKEN, BUNNY_PULLZONE_ID, BUNNY_ACCESS_KEYunset1.3
EDGE_IP_HEADER, EDGE_SECRET_HEADERheader namesCloudFront's1.4
MAIL_PROVIDER_LABELfree textsmtp1.6
TRANSCRIBER_PROVIDERwhisper, transcribe, nonewhisper when a model file exists1.7
OFFSITE_RCLONE_REMOTE, OFFSITE_BUCKETunset1.10
OTEL_EXPORTER_OTLP_ENDPOINTURLunset (telemetry off)3.1
SENTRY_DSN, VITE_SENTRY_DSNURLunset (errors off)3.2

9. Time and order

PhaseAgent daysRuns alongside production plan
0. Decisions and accountshumans, 1 to 2 daysIts Phase 0
1. Missing seams, secrets, backups4Its Phase 1 (share the Dockerfile, logs, flags, health work)
2. Image, Kamal, publish script2Its Phase 1.12 and Phase 3
3. OpenTelemetry, errors, outside eyes2Its Phase 2 Observability stack
4. DNS in repo, mirrors1Its Phase 2 Edge stack
5. Register and six drills3Its Phase 4 (staging exists by then)
Totalabout 12 agent days

If only one thing can be done: Phase 1 item 1.10, the off-site backup and restore drill.

●  Have your own?

// Publish your own markdown.

Write your own
Thnkrr: Swappable Suppliers, the Build Plan · DocHouse