Skip to main content

The Factory — Architecture & Playbook, v1

Date: 2026-05-02 · Author: Sauna synthesis for Adrian · Status: v1 draft, canonical once merged Supersedes: factory_core_architecture.md, STAGE_6_ONWARDS_PLAN.md, FACTORY_STRATEGIC_REVIEW.md, scattered STAGE_* / PHASE_* docs at repo root Subsumes: docs/supervisor/ARCHITECTURE.md (v2.1) as the authoritative deep-dive for Part I §3.4 and §3.5 Fridge: docs/supervisor/FRIDGE.md — the 10 operating rules are non-negotiable and override this document wherever they appear to conflict
This document is the single source of truth for what The Factory is, how it works, and how to operate it. If a statement here conflicts with an older doc, this document wins. If a statement here conflicts with docs/supervisor/FRIDGE.md, FRIDGE wins.

Table of contents

Part I — Architecture (what the system is)
  1. Mission, principles, and scope
  2. Portfolio of apps
  3. Platform layers
  4. Cross-cutting concerns
  5. Delivery lifecycle
  6. Governance
Part II — Playbooks (how to operate it)
  1. Add a new app to the portfolio
  2. Ship a new version of a shared package
  3. Rotate a secret
  4. Respond to a Sentry spike
  5. Debug a migration drift
  6. Author a supervisor template
  7. Resolve an open decision
  8. Onboard a new agent
Part III — Gaps & roadmap
  1. Gap register
  2. Roadmap: current → steady state
  3. Appendices

Part I — Architecture

1. Mission, principles, and scope

1.1 Mission

The Factory is a multi-app software platform where shared infrastructure is versioned as code, apps are clean independent products that plug into the platform, and an AI-token-metered supervisor drives most of the operational lifecycle — matched templates, scoped JWTs, receipts on every step, canary on every deploy. The pitch: every fix in the platform layer simplifies 4–7 downstream apps in one PR. Every app benefits from every platform improvement. The supervisor makes the non-creative parts of operations disappear so human attention is on product decisions, not ticket pushing.

1.2 Design principles

Inherited from factory_core_architecture.md (still valid):
  • Factory Core owns the plumbing; apps own the product. No business logic in @latimer-woods-tech/* packages. No platform responsibilities in app repos.
  • Distributed packages, not a monorepo. Each app is its own repo with pinned dependencies. Selling, transferring, or open-sourcing any single app is a clean handoff.
  • Pinned exact versions + Renovate automation. No ^ / ~ ranges on platform packages. Upgrades are deliberate, tested, and auditable.
  • Cloudflare Workers is the only runtime. No per-app AWS, no Node servers, no Next.js. Hono as the router, Drizzle as the ORM, JWT self-managed via Web Crypto. Stable stack.
  • Sentry is the only error/observability platform. One org, one project per app.
  • PostHog + first-party factory_events for analytics. Behavioral data in PostHog, business events in Neon.
  • Resend for email, Stripe for billing, Telnyx/Deepgram/ElevenLabs for voice. One vendor per capability unless there’s a concrete forcing reason to fan out.
Added in 2026-Q2:
  • Template-grounded supervisor, not generative. See docs/supervisor/ARCHITECTURE.md §5.5.
  • Every LLM call is metered and routed through AI Gateway. Single ledger, per-project budgets, per-run hard cap.
  • Security is confused-deputy-aware. Issue bodies are untrusted data; tool calls are schema-bounded; JWTs are short-lived and scoped per tool class.
  • Put the rules on the fridge. docs/supervisor/FRIDGE.md is readable by any agent or human landing in the repo; it takes 2 minutes to read.

1.3 Scope

In scope for v1:
  • The supervisor-eligible apps declared by the live service and capability registries
  • Every shared package discovered from packages/*/package.json; generated docs carry the current count and dependency order
  • The supervisor control plane (scheduled Sauna Phase-1; apps/supervisor Worker Phase-2)
  • The Dreamstate spec plane
  • All CI/CD, observability, cost, and secrets infrastructure
Out of scope for v1, tracked for future:
  • wordis-bond (compliance pending; hard-locked from automation)
  • focusbro (AdWords acceptance pending; not migrated to Latimer-Woods-Tech org yet)
  • ijustus, cypher-healing, the-calling, neighbor-aid (design-stage; no active product surface)
  • xpelevator (utility; not a product)
  • AI tokens as a monetized SKU (revisit after 6 months of clean supervisor operation)
  • Machine Payments Protocol (supervisor autonomously provisioning its own infra via Stripe identity — not in 2026)

1.4 Audiences

This doc is written for four audiences simultaneously:
  • Adrian and future CODEOWNERS — the humans who set strategy, review Red-tier PRs, and resolve decisions.
  • Sauna (this instance) — the primary autonomous planner/drafter.
  • Scheduled supervisor — the future daily-fired Sauna session (Phase-1) or Worker (Phase-2).
  • Copilot / other autonomous agents — parallel workers on green-list issues.
Wherever instructions apply to only one audience, the section header says so.

2. Portfolio of apps

2.1 Active portfolio

AppProductDomainRepoMaturitySupervisor accessStrategic role
HumanDesignselfprime.net — practitioner synthesis platformselfprime.net, api.selfprime.netLatimer-Woods-Tech/HumanDesignProduction, revenue-live (Individual + Practitioner + Agency tiers)Approved — read + limited mutations via /adminRevenue anchor; primary LLM consumer; template source for supervisor
videokingcapricast.com — short-form creator monetization (NicheStream brand)capricast.com, api.capricast.comLatimer-Woods-Tech/capricastBeta, deployed; Stripe products liveApproved (Yellow)Video pipeline reference; template source
xico-cityxicocity.com — DJMEXXICO artist platformxicocity.comLatimer-Woods-Tech/xico-cityFoundation + GCP Cloud Run processor liveApproved (Yellow)GCP + Cloud Run pattern; artist onboarding template
factoryapunlimited.com — the platform itselfapunlimited.comLatimer-Woods-Tech/factoryPhase 5 complete, Phase 6+ in flightApproved (Green + Yellow)Shared packages, reusable workflows, supervisor runtime
Admin StudioInternal operator control planeapunlimited.com, api.apunlimited.comLatimer-Woods-Tech/Factory (apps/admin-studio*)ProductionHuman-operated; Supervisor proposes through governed APIsCanonical decision, health, deploy, capability, and audit console

2.2 On hold

AppStateReasonFinishing gate
wordis-bondEngine built, feature-completeFDCPA/TCPA compliance riskLegal + business decision: de-risk scope, license, or shelve. Mechanically locked from supervisor — CODEOWNERS + service-registry + supervisor denylist.
focusbroMostly completeGoogle AdWords acceptance pendingAdWords approval arrives. Then: migrate to Latimer-Woods-Tech org if owner agrees.

2.3 Design-stage

AppStateFuture scope
ijustusDesign-stage repoBooking + practitioner service product
cypher-healingDesign-stage repoCommunity / practitioner network
the-callingDesign-stage repoCreator platform
neighbor-aidIdea-stage, scaffold only (Hyperdrive pointer is cosmetically wrong, no code reads it)Local services marketplace. Revisit Q3 2026.
xpelevatorUtility repoNot a product; internal tool

2.4 Per-app canonical facts

Complete canonical identifiers live in §17 (Appendix). Every app entry in §2.1 maps 1:1 to a row in the service registry at docs/service-registry.yml and to a capabilities.yml at the app repo root (once SUP-3.2 lands).

3. Platform layers

Five layers, bottom-up. Each layer has a single responsibility and can change versions without the one above being aware until it chooses to upgrade.
┌─────────────────────────────────────────────────────────────────┐
│  L5: Spec plane — Dreamstate (specs → kanban issues)            │
├─────────────────────────────────────────────────────────────────┤
│  L4: Control plane — Supervisor (planner, executor, verifier)   │
├─────────────────────────────────────────────────────────────────┤
│  L3: Reusable workflows (_app-ci, _app-deploy, _prod-canary…)   │
├─────────────────────────────────────────────────────────────────┤
│  L2: Shared packages (@latimer-woods-tech/*)                     │
├─────────────────────────────────────────────────────────────────┤
│  L1: Runtime (Cloudflare + GCP + Neon + Sentry + Stripe + …)    │
└─────────────────────────────────────────────────────────────────┘

3.1 L1 — Runtime

Cloudflare is the primary runtime host. Everything that handles a request runs on Workers. Durable Objects provide stateful long-running supervisor sessions and single-writer locks. Hyperdrive proxies to Neon. R2 is object storage (videos, media, audit logs). KV is cache. Vectorize is embeddings (fallback memory). AI Gateway fronts every LLM call for caching + rate-limit + cost log. GCP is the only non-Cloudflare compute, restricted to work that can’t run in Workers:
  • factory-495015 / Cloud Run processor (xico-city media transcoding; ffmpeg on real Chromium)
  • Vertex AI (Gemini 2.5 Pro long-context fallback for the supervisor planner)
  • Service accounts: factory-sa (owner, legacy; rotated at SUP-3 exit), supervisor-sa (Vertex-only least-privilege, minted at SUP-1.2)
Neon is the only Postgres. One Neon project per app; production branch per project. Connection strictly via Hyperdrive binding — never raw connection string in app code. Multi-tenant apps use Row-Level Security; no schema-per-tenant. Sentry is the only error + perf platform. Org latwood-tech. One project per worker. Sourcemaps uploaded on every deploy (see §4.4 for when this lights up fully). Stripe is the only payments platform. One account, one product catalog, one webhook endpoint per business-unit. Stripe Radar routes fraud-ish signals to a webhook worker that files issues. External AI providers:
  • Anthropic (primary for synthesis + planner + verifier)
  • Gemini via Vertex (long-context planner fallback only, via AI Gateway routing)
  • Groq (Haiku-equivalent verifier fallback, small-call fallback)
  • OpenAI, xAI: credentials exist but no workload currently routed to them. Kept for experimentation.

3.2 L2 — Shared packages

All packages published to registry.npmjs.org under @latimer-woods-tech/* scope (19 packages at v0.2.0 as of 2026-05-01; a few going to v0.3.0 in SUP-2 and SUP-3). Infra tier (no business logic, never changes meaning per-app):
PackageRole
errorsStandard error hierarchy; typed HTTP responses
loggerStructured logging, request-id propagation
monitoringSentry integration
authJWT via Web Crypto
neonHyperdrive-bound Drizzle client
testingVitest + mock factories + test helpers
deployWrangler scripts, scaffold helpers
Capability tier (shared business primitives):
PackageRole
stripeSubscription lifecycle, webhook processing
emailResend transactional + drip
analyticsPostHog + first-party factory_events
crmLead tracking, MRR
complianceTCPA/FDCPA primitives (live but only consumed by wordis-bond when that unlocks)
telephonyTelnyx + Deepgram + ElevenLabs
llmAI Gateway-routed provider chain (bumping to 0.3.0 in SUP-2)
llm-meterD1 ledger + per-run budget (new in SUP-2.2)
contentCMS primitives
copyLLM-generated copy
seoSEO metadata
socialSocial cross-post
adminHono router mounted at /admin; side_effects-aware routing (bumping to 0.3.0 in SUP-3.1)
videoCloudflare Stream + R2 wrappers
scheduleVideo calendar + priority queue
Dependency order is in CLAUDE.md — don’t invert it. errors is root; every other package depends on it either directly or transitively.

3.3 L3 — Reusable workflows

Hosted on factory, callable from any app repo with a 5-line caller workflow. The golden rule from 2026-04-30 holistic reassessment: one change to a reusable workflow should propagate to every app without touching their repos. The sprawl of 40+ copy-paste workflows was exactly what this layer prevents.
WorkflowPurposeStatus
_app-ci.ymltypecheck + lint + test + coverage; concurrency group per refLive
_app-deploy.ymlwrangler deploy + Sentry release + sourcemap upload + health probeLive
_post-deploy-verify.yml/health curl + optional smoke + rollback on failLive
_app-reliability-gate.ymlCVE + P0-blocker + coverage regression checks (SYN-2)Merged 2026-05-02
_app-prod-canary.ymlPost-deploy canary ride + Sentry spike rollback (SYN-3)Merged 2026-05-02
_app-ci-pnpm.yml / _app-deploy-pnpm.ymlpnpm variant for videoking (VK-7/VK-9)Live
Caller shape every app uses:
jobs:
  ci:
    uses: Latimer-Woods-Tech/factory/.github/workflows/_app-ci.yml@main
    secrets: inherit
App repos don’t own pipeline logic; they own the intent signal.

3.4 L4 — Supervisor control plane

See docs/supervisor/ARCHITECTURE.md v2.1 for full depth. Summary here: Phase 1 (Weeks 1–6): scheduled Sauna session runs daily, template-matches approved-source issues, executes via scoped JWTs, opens PRs, rides canary, closes runs with receipts. Phase 2 (after SUP-5 exit): apps/supervisor Cloudflare Worker with SupervisorDO (Durable Object + Facets) + LockDO singleton per app + memory dual-write + template stats ledger + full tool surface. Phase 2 is an upgrade path, not a prerequisite. If Phase 1 handles the load cleanly for two months, Phase 2 is optional. Template library (docs/supervisor/plans/*.yml) is the brain. Every template is code: versioned, linted, fixture-tested, quality-tracked. No generative planning. Ever. Trust tiers: Green (docs/**, *.md, session/**) auto-merge on blessed templates; Yellow (apps/web/**, non-critical routes) auto-PR + auto-merge on CI + plan-approval; Red (workflows, packages, migrations, Stripe code, prod Wrangler) always human.

3.5 L5 — Dreamstate spec plane

The layer above the supervisor. Intent becomes structured work items. Sources:
  • Human-authored issues on the LatWood Operations board (default, forever).
  • documents/factory/dreamstate/<app>/<feature>/spec.yml files processed hourly by dreamstate-to-issues.mjs (ships in SUP-5).
  • Sentry / Stripe webhook workers filing issues on production signals.
Only issues with supervisor:approved-source are supervisor-eligible. Factory is public; anyone can file an issue; random issues are quarantined for CODEOWNER triage. The Dreamstate schema is intentionally simple — intent + capabilities_required + capabilities_exposed + acceptance_gates + non_goals. It is NOT a full product specification; it’s a structured hand-off from “what” to “how.”

4. Cross-cutting concerns

4.1 Identity & access

Principals:
PrincipalScopeRotation cadence
Adrian’s GitHub user (adrper79-dot)Everything; owner of Latimer-Woods-Tech orgN/A (identity, not secret)
factory-cross-repo GitHub App (ID 3560471)Installed on adrper79-dot + Latimer-Woods-Tech (after SUP-1.1)App-installation tokens auto-rotate hourly
GH_PAT (workflow scope, stored conn_pvMtrQjxhkoZ)Legacy for actions; increasingly replaced by App tokensQuarterly; review at each phase exit
GH_PROJECT_TOKEN org secretGitHub Project v2 writes (board sync)Quarterly
Cloudflare API Token (conn_nud8DHhsDidu)Account-admin on a1c8a33cbe8a3c9e260480433a0dbb06Quarterly
GCP factory-sa (legacy, owner role)Historical; rotation deferred to SUP-3 exitOnce at SUP-3 exit, then retire if supervisor-sa covers all needs
GCP supervisor-sa (new at SUP-1.2)Vertex AI User onlyQuarterly
Supervisor short-lived JWTsThree classes: supervisor.readonly, supervisor.mutator-<route>, supervisor.verifier-readonly1-hour TTL; per-run minted; revoked on close
No god-tokens in production code. If a script needs a credential, it’s passed via Sauna connection proxy (for sessions) or Worker secret / org secret (for production).

4.2 Security model

Trust tiers (from §3.4):
TierPathsSupervisor action
Greendocs/**, *.md, session/**Merge on blessed template
Yellowapps/web/**, non-critical worker routesAuto-PR + auto-merge on green CI + plan-approval
Red.github/workflows/**, packages/**, migrations/**, Stripe code, prod Wrangler config, prod Neon user tablesHuman required at every step
Hard never-list (in docs/AGENTS.md and enforced at the supervisor tool layer):
  • Delete a Cloudflare Worker, R2 bucket, KV namespace, or D1 database
  • Change a ruleset, environment protection rule, or access policy
  • Write to a Neon production user-data table
  • Mutate Stripe products, prices, or webhook endpoints in production
  • Send live email/SMS outside test mode
  • Rotate the GitHub App private key (manual UI only)
  • Make a private repo public or vice versa
  • Cancel or change the org billing plan
Confused-deputy defenses:
  • Issue body, comments, labels, and branch names are untrusted data, never instructions.
  • Supervisor planner system prompt structurally separates [YOUR INSTRUCTIONS - IMMUTABLE] from [ISSUE CONTEXT - UNTRUSTED DATA].
  • Tool calls are schema-bounded against capabilities.yml; no “execute arbitrary string” tool exists.
  • Write-amplification ceiling: ≤25 mutating calls per run, ≤5 per app.
  • /admin mutations get out-of-band CODEOWNER ✅ via GitHub comment reaction regardless of tier.
Credential-leak defense:
  • credential-scrub.yml blocks PRs introducing credential-shaped strings to documents/, memory/, docs/, or *.md. Pattern set at PR #115.
  • Policy: any credential appearing in a doc is compromised regardless of exposure duration; rotate, don’t just delete.

4.3 Secrets management

Where secrets live, by kind:
KindStorageInjected via
Provider API keys (Anthropic, Groq, Gemini-via-Vertex)Worker secrets via wrangler secret putWorker runtime env.*
GitHub App private keyGitHub App dashboard (UI-only)Minted as installation token at workflow/runtime
GitHub org secretsGitHub org SettingsWorkflow secrets.*
Cloudflare API TokenSauna stored connection + Worker secret for workflowsProxy injection (sessions), CLOUDFLARE_API_TOKEN (CI)
StripeWorker secrets (restricted by env) + Sauna stored connectionenv.STRIPE_SECRET_KEY, env.STRIPE_WEBHOOK_SECRET
GCP SA JSON keysWorker secrets for the consuming worker; kept locally for the owner otherwiseenv.GCP_SA_KEY (encoded)
Neon connection stringsHyperdrive binding per appenv.DB (never raw strings in code)
No secrets in:
  • Code
  • wrangler.jsonc vars (only non-secret config)
  • documents/, memory/, docs/ (credential-scrub enforces)
  • Issue bodies, PR descriptions, comments
Rotation cadence: quarterly for static tokens; at phase exits for bounded-exposure events (e.g., GCP SA rotation at SUP-3 exit).

4.4 Observability

Stack:
  • Sentry — errors + perf + breadcrumbs + sourcemaps. Org latwood-tech. One project per worker (10 live projects).
  • PostHog — product analytics. One project per app.
  • factory_events — first-party business events table in Neon (factory-core DB). Everything material (signup, payment, webhook, deploy, rollback) writes a row.
  • llm_ledger — D1 table owned by @latimer-woods-tech/llm-meter (ships SUP-2.2). Every LLM call writes a row keyed on (project, actor, run_id, yyyy-mm).
  • template_stats — D1 table (ships SUP-3.4). Template hit-rate, revert-rate, blessed status.
  • supervisor_runs / supervisor_steps / supervisor_locks_audit — D1, per-run audit trail.
  • Pushover (conn_iR1TgasqajZH) — morning digest + Sentry SMS spike + budget-paused alerts.
  • Telnyx SMS — backup alert channel for production-critical Sentry issues.
Required on every deploy:
  1. Sentry release created with the merge SHA as the release name
  2. Sourcemaps uploaded for every worker (retroactive fix: many existing workers still need this wired — tracked as an item in the gap register §15)
  3. /health curl passes before traffic shifts
  4. Canary rides for N minutes (default 30) on new releases before marking stable

4.5 Cost & budgets

Two-phase budget policy (from docs/supervisor/ARCHITECTURE.md §6):
  • Calibration (weeks 2–4): no monthly caps. Per-call ceiling 50k tokens. Per-run hard ceiling $5 USD. Every call metered to llm_ledger.
  • Steady-state (week 5+): monthly caps set at observed p95 × 1.5 per (project, actor). Email alert at 75%. Hard stop at 100%. Monthly review.
Cost drivers to watch (from AI_CORE_AUDIT.md):
  • HumanDesign Practitioner tier at scale: ~0.043/synthesisblended;220.043/synthesis blended; 22% LLM COGS on 97 tier at 500 syntheses/mo.
  • Supervisor planner: Sonnet 4.5 calls with growing RAG context; mitigate with prompt caching + switching to Gemini long-context at >150k tokens.
  • Video pipeline (videoking): transcoding on CF Stream at ~$0.005/minute of source. Monitor when volume scales.
Non-LLM cost budgets tracked separately:
  • Cloudflare Workers: ~$5/mo per account (current Pro plan). Grows with request volume.
  • Neon: ~$19/mo per project at the Scale tier. 14 projects currently.
  • GCP: ~$30/mo for Cloud Run idle (min=1 on xico-city processor) + Vertex AI usage (starts in SUP-2).

4.6 Data plane

Neon projects (Adrian org org-withered-wave-19602339, 13 projects — reconciled against live neonctl activity 2026-06-17):
ProjectPurposeState
HumanDesign (divine-grass-42421088)selfprime prod + stagingProduction live; migration drift bug tracked as HD#65
MEXXICO_CITY (lively-cake-48808698)xico-city / DJMEXXICOFoundation live
THE_FACTORY (morning-dust-88304389)Factory core (cross-app CRM, compliance, factory_events)Provisioned
nichestream (dry-poetry-91897020)videoking / capricastLive
factory-network (cool-grass-57951356)network layer (capricast IdP / factory-core-api)Live (created 2026-06-09)
delicate-shadow (delicate-shadow-17989842)wordis-bond-factoryLive — compute observed 2026-06-17 (previously mislabeled “retire”)
COH (curly-tree-61268761)cipherofhealing / coh workerLive per service-registry (previously mislabeled “retire”)
WordIsBond (misty-sound-29419685)wordis-bond (legacy production branch)Semi-dormant; last probe 2026-06-10 — verify before retiring
prime-self-factory (withered-pine-66999393)Legacy prime-self pre-org-migrationArchive candidate — but compute observed 2026-06-17 10:06; trace consumer before archiving
kairoscouncil (divine-breeze-43656605)kairoscouncil (living card game)Active Phase 0 build — engine merged 2026-07-04, CI green (previously mislabeled “retire”). Do NOT retire; onboarding to Factory infra in progress
the-calling-factory (icy-poetry-46600213), THECALLING (floral-rain-53649452), XPELEVATOR (aged-butterfly-52244878)Design-stage or legacyReview + retire at SUP-5 cleanup
Retired 2026-06-17: gemini-staging (fancy-mouse-91117889) + gemini-production (misty-bonus-64352779) — deleted after confirming archived branches + only wind-down ops (tenant_detach/timeline_archive 2026-06-10), no live compute. Org dropped 15→13 projects.
Connection rule: apps connect to Neon only via Hyperdrive binding (env.DB in Workers). Raw connection strings never appear in app code or wrangler.jsonc. Migrations: Drizzle per app. workers/src/db/migrations/NNN_*.sql numbered monotonically. Applied by workers/src/db/migrate.js invoked either locally (with NEON_DATABASE_URL env) or by a deploy-step workflow (SUP-1.4 migration-drift-guard will catch gaps). Multi-tenancy: Row-Level Security on all shared-tenant tables. app.tenant_id session variable set by @latimer-woods-tech/neon’s withTenant(db, tenantId) helper. Policies evaluate at every SELECT / UPDATE. Backups: Neon point-in-time restore is built-in. No additional backup layer currently. For Stripe/financial-grade durability, also dual-log critical rows to factory_events in the factory-core project.

4.7 Compliance posture

Current exposure:
  • Stripe PCI — Handled by Stripe Elements; Factory never sees raw PAN. SAQ-A eligible.
  • GDPR / CCPA@latimer-woods-tech/compliance exposes a DSR (data subject request) primitive; not yet wired into all apps (gap).
  • TCPA — Relevant only to wordis-bond (engine designed for it) and any telephony use in other apps. @latimer-woods-tech/compliance provides consent logs + opt-out enforcement; wordis-bond is the only consumer.
  • FDCPA — Same story: wordis-bond-specific. Hard-locked from automation until legal clarity.
  • HIPAA — Not in scope. HumanDesign Energy Blueprint is not PHI.
  • State privacy laws (CA, VA, CO, CT, UT, NV, TX) — Relevant for HumanDesign Practitioner tier (clients are potentially residents). DSR path needs to be E2E tested before Q3 2026.
Open compliance gaps (tracked in §15):
  • DSR E2E path per app (HumanDesign priority)
  • Data-retention policy documentation
  • Incident response runbook for breach (a stub exists; needs legal review)

5. Delivery lifecycle

Stage 6 (Primus design system) is in flight — docs/architecture/PRIMUS.md is the authority for the token/component/a11y/forms/icons rollout.

5.1 The 9-step flow

From 2026-05-01_KANBAN_TO_PROD_FLOW.md. This is how a work item moves from “filed” to “deployed and verified”:
1. Issue filed          → 2. Added to board     → 3. Agent claims
  ↓                        ↓                        ↓
[GitHub Issue]           [Project v2 #1]         [agent:claimed:X]
                         [Status: Todo]          [Status: In Progress]

4. Agent opens PR       → 5. CI validates       → 6. Required review
  ↓                        ↓                        ↓
[Branch pushed]          [_app-ci.yml]           [CODEOWNERS check]
[Links "Closes #N"]      [_app-reliability-gate] [mergeable_state: clean]

7. PR merges            → 8. Deploy fires       → 9. Verified live
  ↓                        ↓                        ↓
[squash to main]         [_app-deploy.yml]       [/health probe]
[Issue auto-closes]      [wrangler deploy]       [_post-deploy-verify]
[Status: Done]           [Deploy SHA captured]   [_app-prod-canary]
                                                 [rollback on fail]
Today: 8 of 9 steps run hands-off for Green-tier work after MA-0 closed. Step 1 (issue filing) stays human by design; automating it prematurely creates noise.

5.2 Tier paths (exhaustive)

TierPaths that matchWho merges
Greendocs/**, *.md, session/**, documents/**, .github/ISSUE_TEMPLATE/**Supervisor on blessed template; else CODEOWNER
Yellowapps/*/src/** (non-critical routes), client/**, app-level wrangler.jsonc (staging only), tests/**, workers/src/handlers/** (non-billing/admin)Supervisor on plan-approval; CODEOWNER review before auto-merge
Red.github/workflows/**, packages/**, workers/src/db/migrations/**, workers/src/handlers/billing*, workers/src/handlers/admin*, workers/src/handlers/stripe*, prod wrangler.jsonc, CODEOWNERS, .github/CODEOWNERS, any capabilities.yml side_effects=write-external changeCODEOWNER, always

5.3 CODEOWNERS (target state after MA-4)

# Red-tier default
*                                    @adrper79-dot

# Yellow-tier paths where factory-cross-repo can auto-merge on green CI
apps/*/src/**                        @adrper79-dot @factory-cross-repo
client/**                            @adrper79-dot @factory-cross-repo
tests/**                             @adrper79-dot @factory-cross-repo

# Green-tier paths where factory-cross-repo can merge on blessed template
docs/**                              @adrper79-dot @factory-cross-repo
*.md                                 @adrper79-dot @factory-cross-repo
session/**                           @adrper79-dot @factory-cross-repo

# Explicit Red-tier guards (belt and suspenders)
.github/workflows/**                 @adrper79-dot
packages/**                          @adrper79-dot
workers/src/db/migrations/**         @adrper79-dot
workers/src/handlers/billing*        @adrper79-dot
workers/src/handlers/admin*          @adrper79-dot
workers/src/handlers/stripe*         @adrper79-dot
capabilities.yml                     @adrper79-dot
wrangler.jsonc                       @adrper79-dot

5.4 Canary + rollback protocol

Every production deploy runs _app-prod-canary.yml:
  1. Deploy new version to 10% of traffic (or equivalent for single-worker apps: deploy, then curl /health + key routes).
  2. Watch Sentry for new issues + error-rate spike over baseline (default 30 min).
  3. If clean: promote to 100% (no-op for single-worker pattern).
  4. If spike: auto-rollback via wrangler rollback <prior_deployment_id> + Pushover alert.
Rollback is always reversible — every deploy tagged with the prior SHA so wrangler rollback is one command.

5.5 Merge queue

Optional; activated after merge queue triggers are added to all gating workflows. Factory has the ruleset primitives; just needs merge_group: triggers on validate, app ci.yml, and deploy paths (tracked in §15).

6. Governance

6.1 Decision gating

Open architectural / policy decisions are filed as GitHub issues with label decision:needs-human. They are NOT resolved in chat, documentation, or Slack. They require one of:
  • A CODEOWNER ✅ reaction on the issue, OR
  • A merged PR updating docs/supervisor/DECISIONS.md with the resolved outcome.
Currently open: O1 (supervisor runtime location), O2 (memory backend default), O3 (template authoring surface). All three block SUP-3 work and must resolve before Week 3.

6.2 ADRs

Non-trivial design decisions get an ADR at docs/adr/NNNN-<slug>.md. Numbering starts at 1001 (Phase 4). Template in docs/ARCHITECTURAL_DECISION_RECORDS.md. ADRs are immutable once Status: Accepted. Revision = new ADR that supersedes, not editing in place.

6.3 Fridge rules

docs/supervisor/FRIDGE.md has 10 operating rules that apply to every agent (human or AI) on every PR. The PR template checklist forces ack. The credential-scrub, capabilities-lint, and template-suite workflows enforce mechanically. If FRIDGE conflicts with this document: FRIDGE wins. This doc can be revised by PR; FRIDGE revisions require an ADR.

6.4 Memory single-writer

Per MA-8 (factory#86): only one Sauna instance edits memory/*.md at a time. Running two Saunas in parallel writing memory creates races. Mechanical enforcement (shipped in MA-8):
  1. supervisor-loop.yml concurrency group (group: supervisor-loop, cancel-in-progress: false) — queues supervisor runs so two instances never execute simultaneously. The second run waits until the first completes; no memory-write tick is lost.
  2. memory-single-writer.yml PR check — blocks any PR that edits memory/*.md when another open PR already has pending memory edits. Posts a blocking comment identifying the conflicting PR(s) and fails the required status check.
  3. CODEOWNERS memory/** entry — pins @adrper79-dot as sole required reviewer for all memory/ changes, so the branch-protection review gate fires on every memory write regardless of tier.
When the supervisor runs daily, it becomes an additional memory writer. A second Sauna instance must treat memory/*.md as read-only and propose edits as PRs; the memory-single-writer check enforces this mechanically.

Part II — Playbooks

Each playbook is a runbook for one common operation. Copy-paste friendly. Assume you’re authenticated and have the fridge rules in mind.

7. Playbook: add a new app to the portfolio

Prerequisite: a real product decision that the app exists. Skip if this is a “maybe” — too many design-stage repos already. Steps:
  1. Decide strategic tier (revenue-facing, utility, etc.) and supervisor access level (none / Green / Yellow).
  2. Use scripts/scaffold.mjs in factory to create the repo under Latimer-Woods-Tech.
  3. Apply the standard ruleset via setup-all-apps.mjs (branch protection, required checks).
  4. Add CODEOWNERS matching §5.3 tier paths, adjusted for this app’s specific Red-tier paths.
  5. Add caller workflows pointing at _app-ci.yml, _app-deploy.yml, _post-deploy-verify.yml, _app-reliability-gate.yml, _app-prod-canary.yml.
  6. Provision Neon project in Adrian org; create production branch; wire Hyperdrive binding in wrangler.jsonc.
  7. Create Sentry project + DSN org secret.
  8. Add row to docs/service-registry.yml with base_url, consumers, supervisor access.
  9. Add capabilities.yml at repo root declaring every /admin route the supervisor can call. Strict slot typing. side_effects per route.
  10. Add to this document’s §2.1 portfolio table.
  11. File tracking epic on LatWood Operations board linking back to §2.
Do not skip steps. An app without a capabilities.yml is invisible to the supervisor. An app without a ruleset can have force-pushed main.

8. Playbook: ship a new version of a shared package

  1. Create a branch feat/<package>-<summary> in factory.
  2. Edit the package under packages/<name>/.
  3. Run pnpm -F @latimer-woods-tech/<name> build && pnpm -F @latimer-woods-tech/<name> test locally.
  4. Bump version in the package’s package.json (semver: patch for fixes, minor for additive, major for breaking).
  5. Update CHANGELOG.md in the package directory.
  6. Open PR against factory main. Label: priority:P1 (or P0 for security), phase as appropriate. Include blast-radius list of consumer apps.
  7. CI runs _app-ci.yml + _app-reliability-gate.yml.
  8. On merge: factory’s publish.yml workflow tags the package and publishes to registry.npmjs.org.
  9. Renovate opens PRs in every consumer app to bump the pinned version.
  10. Review consumer bumps per app (Red on packages; humans merge).
  11. For breaking changes (major bump): write a migration guide in docs/packages/<name>/MIGRATION-<prev>-to-<new>.md.
Never edit a package version directly on main without going through this flow. Broken package publishes cascade.

9. Playbook: rotate a secret

Pick the kind:

9.a GCP service-account key

  1. GCP console → IAM → Service Accounts → select SA → Keys → Add Key → Create new key (JSON). Download securely.
  2. Map downstream consumers: grep -r "factory-sa\|supervisor-sa" ~/code/ + check wrangler secret list on every worker.
  3. Update every consumer (worker secrets via wrangler secret put; GitHub Actions org secrets via gh secret set; Sauna stored connection via Settings UI).
  4. Verify each consumer authenticates with the new key (whoami-style call per service).
  5. GCP console → revoke the old key.
  6. Document the rotation in docs/runbooks/secret-rotation.md with the date + consumers touched.

9.b GitHub App private key

UI-only, manual. docs/runbooks/secret-rotation.md has the step-by-step. Not automatable. Not rotated frequently — do it if compromise suspected, not on a schedule.

9.c GH PAT (workflow scope)

  1. Mint new PAT via https://github.com/settings/tokens with the needed scopes (usually repo + workflow + read:org + write:packages + project).
  2. Update Sauna stored connection conn_pvMtrQjxhkoZ via Settings UI (or replace if UI blocks edit).
  3. Update GH_PAT org secret via gh secret set GH_PAT --org Latimer-Woods-Tech.
  4. Revoke old PAT.

9.d Cloudflare API Token

  1. Cloudflare dashboard → My Profile → API Tokens → Create similar token with the same permissions.
  2. Update conn_nud8DHhsDidu via Sauna Settings.
  3. Update CLOUDFLARE_API_TOKEN org secret.
  4. Revoke old.

9.e Stripe

If restricted key (rk_live_* / rk_test_*): mint new via Stripe Dashboard → Developers → API keys. Update STRIPE_SECRET_KEY (or the specific restricted key secret) at org level. Deploy every consumer app. Revoke old. If webhook secret: rotate endpoint-by-endpoint in Stripe Dashboard → Webhooks. Update STRIPE_WEBHOOK_SECRET. Coordinate so endpoints don’t reject in-flight events during the window.

9.f Anthropic / provider API keys

Mint new via provider dashboard. Update corresponding Worker secret on every consumer worker via wrangler secret put. Revoke old. Fridge rule 2 applies to all rotations: if the key appeared in a doc, the doc exposure is the primary incident; rotate immediately, don’t schedule.

10. Playbook: respond to a Sentry spike

  1. Pushover fires with the issue short-id + link.
  2. Open Sentry → issue → events/latest/. Capture: culprit, stack frames, recent tags, request URL, user count.
  3. If sourcemaps are uploaded: stack has real file:line. Otherwise you need to grep the dist or read the source to find the call site.
  4. Determine blast radius: single user? Single route? All requests?
  5. Decide:
    • Transient (third-party outage, one-off): resolve as auto-resolved with a note. Revisit if it recurs.
    • Code bug: file or find the GH issue; link Sentry. Follow playbook §11 if it’s a migration gap.
    • Degraded state: trigger the degraded-mode feature flag if available; post user-facing status if customer-visible.
  6. If user impact is > 10 users OR revenue-critical: consider rolling back (wrangler rollback <prior_sha>) while investigating.
  7. After fix merges + deploys: resolve the Sentry issue with the commit SHA in the note.

11. Playbook: debug a migration drift

You see a Sentry error like column <x> does not exist or relation <y> does not exist.
  1. Confirm the column/table exists in the repo. grep -r "<column_name>" workers/src/db/migrations/ in the app repo. If it’s there: this is drift, not a missing migration.
  2. Connect to the app’s production Neon via the direct connection string from the Neon dashboard.
  3. Query information_schema.columns (or .tables) to confirm what’s actually in prod.
  4. Read the migration tracking table: SELECT * FROM drizzle.__drizzle_migrations ORDER BY id (or wherever the runner puts it).
  5. Compute the gap: repo latest migration number minus prod applied. Apply missing migrations in order via psql -f OR via the repo’s npm run migrate.
  6. Verify the Sentry error stops firing within 2 hours.
  7. File or update SUP-1.4 (migration-drift-guard) so this never happens silently again.
Full worked example: file://session/hd-65-migration-runbook.md.

12. Playbook: author a supervisor template

Write templates reactively (from real closed issues), not proactively from imagination.
  1. Pick a closed Red-tier or Yellow-tier issue that took the human < 2 hours and had a clear shape.
  2. Read the merged PR diff + commit trail. What files changed? What API calls happened in workflow logs?
  3. Draft docs/supervisor/plans/<slug>.yml following docs/supervisor/TEMPLATE_SPEC.md:
    • triggers (labels_any_of, title_pattern)
    • preconditions (capability_exists)
    • slots with strict validators (type + regex or enum or referential_check)
    • steps with depends_on chains
    • acceptance_gate with verifier_query where possible
    • rollback plan
  4. Create a fixture at tests/supervisor/fixtures/<slug>.yml (a sample issue that should match).
  5. Open PR. template-suite.yml runs match + parameterize + gates against the fixture; must pass.
  6. Review with a CODEOWNER. Template starts unblessed. After 3 clean runs in prod (0 reverts, 0 overrides), it auto-blesses.
Never start a template from scratch without a closed issue as source of truth. Generative imagination is the failure mode.

13. Playbook: resolve an open decision

  1. Open docs/supervisor/DECISIONS.md and find the decision row.
  2. Click through to the linked issue (#110, #111, #112, etc.).
  3. Read the context + options + recommendation.
  4. Either:
    • React ✅ on the issue. The scheduled daily digest picks this up and opens a PR moving the row from “Currently open” to “Resolved” in DECISIONS.md.
    • Open a decision PR directly updating DECISIONS.md. Include the reasoning in the PR body.
  5. Merge the resolution PR. Downstream work (typically a phase exit gate) unblocks.
Decisions don’t close via chat. Ever.

14. Playbook: onboard a new agent

14.a Human CODEOWNER

  1. Grant repo write access under Latimer-Woods-Tech.
  2. Add to CODEOWNERS on paths they’ll own.
  3. Have them read docs/supervisor/FRIDGE.md (5 minutes) and this document’s §1 + §4 + §5 (another 15).
  4. Pair on one Red-tier PR review before they solo.

14.b Second Sauna instance (parallel worker)

  1. MA-8 (memory single-writer) is mechanically enforced: memory-single-writer.yml blocks any PR that edits memory/*.md while another PR already has pending memory edits. The second Sauna must treat memory/*.md as read-only and propose edits as PRs.
  2. Agent claims issues via agent:claimed:sauna-2 label (or similar discriminator).
  3. Same fridge rules apply.
  4. Coordinate via issue comments, not via shared memory.

14.c Third-party autonomous agent (e.g., Copilot)

  1. Give it access scoped to Green-list paths only.
  2. Its commits must carry a trailer identifying the agent for audit traceability.
  3. If it’s App-authenticated: verify the App’s signed-commit requirement matches what the ruleset expects.
  4. Start it on supervisor:approved-source + Green-only issues for the first week.

Part III — Current-state routing

15. Gap register

This architecture document no longer hand-maintains a point-in-time gap table. That table became false while the platform continued shipping. Current gaps are resolved in this order:
  1. docs/supervisor/DECISIONS.md for founder-blocked decisions.
  2. Open GitHub issues carrying status:blocked, priority:*, and ownership labels for executable work.
  3. docs/STATE.md and docs/service-registry.yml for generated and deployed facts.
  4. Docs Health and service-registry validation for detected drift.
Historical gap snapshots remain in Git history and archived planning documents; they are not evidence of current platform state.

16. Roadmap: current → steady state

The executable roadmap lives in the Founder Gate Board and prioritized GitHub issues. Architecture changes land here only after a decision is accepted; planned dates and active work do not. This keeps the architecture stable while allowing the portfolio queue to change daily without creating a second, stale decision system.

17. Appendices

17.a Canonical names + IDs

GitHub org: Latimer-Woods-Tech (https://github.com/Latimer-Woods-Tech) GitHub App: factory-cross-repo, ID 3560471, Client ID Iv23ctoSwlqJBeiMidut, install on adrper79-dot: 128501967 (install on LWT org pending SUP-1.1) LatWood Operations project: PVT_kwDOEL0sNc4BWWtghttps://github.com/orgs/Latimer-Woods-Tech/projects/1 Cloudflare account: a1c8a33cbe8a3c9e260480433a0dbb06 (owner: Adrian) GCP project: factory-495015, project number 891842778224 Neon org: org-withered-wave-19602339 (Adrian) Sentry org: latwood-tech Stripe account: apn_EOhleMX (live mode) Key Sauna stored connections:
  • conn_pvMtrQjxhkoZ — GitHub PAT (workflow scope)
  • conn_nud8DHhsDidu — Cloudflare API Token
  • conn_yF3m9DEuPI8x — GCP SA (known-broken for OAuth minting; use in-script JWT)
  • conn_iR1TgasqajZH — Pushover (primary alerts)
  • conn_C9zi6T2td8mt — Telnyx (SMS backup)

17.b Glossary

  • Blessing — a template reaches blessed status after ≥3 successful runs with 0 reverts and 0 human overrides. Blessed templates skip plan-approval on Green.
  • Calibration phase — weeks 2–4 when LLM usage is metered without monthly caps, only per-run $5 hard stops. Data feeds the steady-state caps.
  • Confused deputy — an attack where an authorized principal (supervisor) is tricked into performing actions on behalf of an unauthorized actor (issue-body prompt injection).
  • Dreamstate — the spec-layer input to the supervisor. Intent in YAML; supervisor translates to issues.
  • Fridgedocs/supervisor/FRIDGE.md. The 10 non-negotiable operating rules. Read first.
  • Hard-never list — actions the supervisor cannot perform regardless of tier or approval. See §4.2.
  • Plan-approval — the gate requiring CODEOWNER ✅ on the planner’s proposed tool-call sequence before EXEC. Required on first 10 runs per template and always on Yellow/Red.
  • Side effects (graded) — capability declaration field: none / read-external / write-app / write-external. Replaces boolean mutating.
  • Source-trust labelsupervisor:approved-source. Required on any issue before the supervisor will pick it up.
  • Template drift / migration drift — code and deployed state disagreeing about schema or interface. The class of bug SUP-1.4 catches.
DocScopeStatus
This document (docs/architecture/FACTORY_V1.md)Whole system + playbooksCanonical, v1
docs/supervisor/ARCHITECTURE.md (v2.1)Supervisor control plane deep diveAuthoritative for §3.4
docs/supervisor/FRIDGE.mdOperating rulesOverrides everything
docs/supervisor/DECISIONS.mdOpen + resolved decisionsLiving; updated per decision
docs/supervisor/EXECUTION_TRACKER.mdPhase-by-phase statusMirror of LatWood Operations
docs/supervisor/TEMPLATE_SPEC.mdTemplate schema + authoring rulesDeep-dive for §12
docs/supervisor/TEMPLATE_BOOTSTRAP_CANDIDATES.mdPR-history analysis for template seedingSUP-3.3 input
docs/CAPABILITY_CONTRACT.mdcapabilities.yml schemaDeep-dive for §3 / §7
docs/service-registry.ymlCanonical service → URL → consumer mapSource of truth
docs/ARCHITECTURAL_DECISION_RECORDS.mdADR template + processHow to add an ADR
docs/adr/NNNN-*.mdIndividual ADRsImmutable once Accepted
docs/AGENTS.mdAgent operating rules for this repoComplements FRIDGE
CLAUDE.mdStanding orders for LLM agentsComplements FRIDGE
factory_core_architecture.mdHistorical: Phase 5 package specSuperseded by §3.2
STAGE_6_ONWARDS_PLAN.mdHistorical: Phase 6+ planSuperseded by §3 + §16
FACTORY_STRATEGIC_REVIEW.mdHistorical: April strategic assessmentSuperseded by this doc
2026-05-01_KANBAN_TO_PROD_FLOW.mdHistorical: 9-step flow descriptionRetained; referenced by §5.1
2026-05-01_MULTI_AGENT_READINESS.mdHistorical: MA-0 gap closure planRetained; MA-0 now mostly closed
AI_CORE_AUDIT.mdHistorical: LLM vendor auditDecision recorded in §4.5; audit retained as reference

17.d Change log

  • 2026-05-02 — v1 initial publication. Consolidates prior architecture docs. Supersedes listed above. Authored by Sauna for Adrian; awaiting CODEOWNER ✅ for canonical status.

How to propose changes to this document

  1. Open a PR updating docs/architecture/FACTORY_V1.md on factory.
  2. Label documentation + priority:P1.
  3. If the change resolves an open decision, also update docs/supervisor/DECISIONS.md in the same PR.
  4. If the change conflicts with FRIDGE rules, stop and open an ADR first (FRIDGE revisions require ADRs).
  5. CODEOWNER review required (Red-tier path by default).
Canonical. v1. Read. Challenge. Revise.