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)- Mission, principles, and scope
- Portfolio of apps
- Platform layers
- Cross-cutting concerns
- Delivery lifecycle
- Governance
- Add a new app to the portfolio
- Ship a new version of a shared package
- Rotate a secret
- Respond to a Sentry spike
- Debug a migration drift
- Author a supervisor template
- Resolve an open decision
- Onboard a new agent
- Gap register
- Roadmap: current → steady state
- 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 fromfactory_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_eventsfor 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.
- 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.mdis 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/supervisorWorker Phase-2) - The Dreamstate spec plane
- All CI/CD, observability, cost, and secrets infrastructure
- wordis-bond (compliance pending; hard-locked from automation)
- focusbro (AdWords acceptance pending; not migrated to
Latimer-Woods-Techorg 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.
2. Portfolio of apps
2.1 Active portfolio
| App | Product | Domain | Repo | Maturity | Supervisor access | Strategic role |
|---|---|---|---|---|---|---|
| HumanDesign | selfprime.net — practitioner synthesis platform | selfprime.net, api.selfprime.net | Latimer-Woods-Tech/HumanDesign | Production, revenue-live (Individual + Practitioner + Agency tiers) | Approved — read + limited mutations via /admin | Revenue anchor; primary LLM consumer; template source for supervisor |
| videoking | capricast.com — short-form creator monetization (NicheStream brand) | capricast.com, api.capricast.com | Latimer-Woods-Tech/capricast | Beta, deployed; Stripe products live | Approved (Yellow) | Video pipeline reference; template source |
| xico-city | xicocity.com — DJMEXXICO artist platform | xicocity.com | Latimer-Woods-Tech/xico-city | Foundation + GCP Cloud Run processor live | Approved (Yellow) | GCP + Cloud Run pattern; artist onboarding template |
| factory | apunlimited.com — the platform itself | apunlimited.com | Latimer-Woods-Tech/factory | Phase 5 complete, Phase 6+ in flight | Approved (Green + Yellow) | Shared packages, reusable workflows, supervisor runtime |
| Admin Studio | Internal operator control plane | apunlimited.com, api.apunlimited.com | Latimer-Woods-Tech/Factory (apps/admin-studio*) | Production | Human-operated; Supervisor proposes through governed APIs | Canonical decision, health, deploy, capability, and audit console |
2.2 On hold
| App | State | Reason | Finishing gate |
|---|---|---|---|
| wordis-bond | Engine built, feature-complete | FDCPA/TCPA compliance risk | Legal + business decision: de-risk scope, license, or shelve. Mechanically locked from supervisor — CODEOWNERS + service-registry + supervisor denylist. |
| focusbro | Mostly complete | Google AdWords acceptance pending | AdWords approval arrives. Then: migrate to Latimer-Woods-Tech org if owner agrees. |
2.3 Design-stage
| App | State | Future scope |
|---|---|---|
| ijustus | Design-stage repo | Booking + practitioner service product |
| cypher-healing | Design-stage repo | Community / practitioner network |
| the-calling | Design-stage repo | Creator platform |
| neighbor-aid | Idea-stage, scaffold only (Hyperdrive pointer is cosmetically wrong, no code reads it) | Local services marketplace. Revisit Q3 2026. |
| xpelevator | Utility repo | Not 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 atdocs/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.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)
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 toregistry.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):
| Package | Role |
|---|---|
errors | Standard error hierarchy; typed HTTP responses |
logger | Structured logging, request-id propagation |
monitoring | Sentry integration |
auth | JWT via Web Crypto |
neon | Hyperdrive-bound Drizzle client |
testing | Vitest + mock factories + test helpers |
deploy | Wrangler scripts, scaffold helpers |
| Package | Role |
|---|---|
stripe | Subscription lifecycle, webhook processing |
email | Resend transactional + drip |
analytics | PostHog + first-party factory_events |
crm | Lead tracking, MRR |
compliance | TCPA/FDCPA primitives (live but only consumed by wordis-bond when that unlocks) |
telephony | Telnyx + Deepgram + ElevenLabs |
llm | AI Gateway-routed provider chain (bumping to 0.3.0 in SUP-2) |
llm-meter | D1 ledger + per-run budget (new in SUP-2.2) |
content | CMS primitives |
copy | LLM-generated copy |
seo | SEO metadata |
social | Social cross-post |
admin | Hono router mounted at /admin; side_effects-aware routing (bumping to 0.3.0 in SUP-3.1) |
video | Cloudflare Stream + R2 wrappers |
schedule | Video calendar + priority queue |
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 from2026-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.
| Workflow | Purpose | Status |
|---|---|---|
_app-ci.yml | typecheck + lint + test + coverage; concurrency group per ref | Live |
_app-deploy.yml | wrangler deploy + Sentry release + sourcemap upload + health probe | Live |
_post-deploy-verify.yml | /health curl + optional smoke + rollback on fail | Live |
_app-reliability-gate.yml | CVE + P0-blocker + coverage regression checks (SYN-2) | Merged 2026-05-02 |
_app-prod-canary.yml | Post-deploy canary ride + Sentry spike rollback (SYN-3) | Merged 2026-05-02 |
_app-ci-pnpm.yml / _app-deploy-pnpm.yml | pnpm variant for videoking (VK-7/VK-9) | Live |
3.4 L4 — Supervisor control plane
Seedocs/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.ymlfiles processed hourly bydreamstate-to-issues.mjs(ships in SUP-5).- Sentry / Stripe webhook workers filing issues on production signals.
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:| Principal | Scope | Rotation cadence |
|---|---|---|
Adrian’s GitHub user (adrper79-dot) | Everything; owner of Latimer-Woods-Tech org | N/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 tokens | Quarterly; review at each phase exit |
GH_PROJECT_TOKEN org secret | GitHub Project v2 writes (board sync) | Quarterly |
Cloudflare API Token (conn_nud8DHhsDidu) | Account-admin on a1c8a33cbe8a3c9e260480433a0dbb06 | Quarterly |
GCP factory-sa (legacy, owner role) | Historical; rotation deferred to SUP-3 exit | Once at SUP-3 exit, then retire if supervisor-sa covers all needs |
GCP supervisor-sa (new at SUP-1.2) | Vertex AI User only | Quarterly |
| Supervisor short-lived JWTs | Three classes: supervisor.readonly, supervisor.mutator-<route>, supervisor.verifier-readonly | 1-hour TTL; per-run minted; revoked on close |
4.2 Security model
Trust tiers (from §3.4):| Tier | Paths | Supervisor action |
|---|---|---|
| Green | docs/**, *.md, session/** | Merge on blessed template |
| Yellow | apps/web/**, non-critical worker routes | Auto-PR + auto-merge on green CI + plan-approval |
| Red | .github/workflows/**, packages/**, migrations/**, Stripe code, prod Wrangler config, prod Neon user tables | Human required at every step |
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
- 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.
/adminmutations get out-of-band CODEOWNER ✅ via GitHub comment reaction regardless of tier.
credential-scrub.ymlblocks PRs introducing credential-shaped strings todocuments/,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:| Kind | Storage | Injected via |
|---|---|---|
| Provider API keys (Anthropic, Groq, Gemini-via-Vertex) | Worker secrets via wrangler secret put | Worker runtime env.* |
| GitHub App private key | GitHub App dashboard (UI-only) | Minted as installation token at workflow/runtime |
| GitHub org secrets | GitHub org Settings | Workflow secrets.* |
| Cloudflare API Token | Sauna stored connection + Worker secret for workflows | Proxy injection (sessions), CLOUDFLARE_API_TOKEN (CI) |
| Stripe | Worker secrets (restricted by env) + Sauna stored connection | env.STRIPE_SECRET_KEY, env.STRIPE_WEBHOOK_SECRET |
| GCP SA JSON keys | Worker secrets for the consuming worker; kept locally for the owner otherwise | env.GCP_SA_KEY (encoded) |
| Neon connection strings | Hyperdrive binding per app | env.DB (never raw strings in code) |
- Code
wrangler.jsoncvars(only non-secret config)documents/,memory/,docs/(credential-scrub enforces)- Issue bodies, PR descriptions, comments
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-coreDB). 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.
- Sentry release created with the merge SHA as the release name
- Sourcemaps uploaded for every worker (retroactive fix: many existing workers still need this wired — tracked as an item in the gap register §15)
/healthcurl passes before traffic shifts- Canary rides for N minutes (default 30) on new releases before marking stable
4.5 Cost & budgets
Two-phase budget policy (fromdocs/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.
AI_CORE_AUDIT.md):
- HumanDesign Practitioner tier at scale: ~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.
- 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 orgorg-withered-wave-19602339, 13 projects — reconciled against live neonctl activity 2026-06-17):
| Project | Purpose | State |
|---|---|---|
HumanDesign (divine-grass-42421088) | selfprime prod + staging | Production live; migration drift bug tracked as HD#65 |
MEXXICO_CITY (lively-cake-48808698) | xico-city / DJMEXXICO | Foundation live |
THE_FACTORY (morning-dust-88304389) | Factory core (cross-app CRM, compliance, factory_events) | Provisioned |
nichestream (dry-poetry-91897020) | videoking / capricast | Live |
factory-network (cool-grass-57951356) | network layer (capricast IdP / factory-core-api) | Live (created 2026-06-09) |
delicate-shadow (delicate-shadow-17989842) | wordis-bond-factory | Live — compute observed 2026-06-17 (previously mislabeled “retire”) |
COH (curly-tree-61268761) | cipherofhealing / coh worker | Live 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-migration | Archive 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 legacy | Review + retire at SUP-5 cleanup |
Retired 2026-06-17:Connection rule: apps connect to Neon only via Hyperdrive binding (gemini-staging(fancy-mouse-91117889) +gemini-production(misty-bonus-64352779) — deleted after confirming archived branches + only wind-down ops (tenant_detach/timeline_archive2026-06-10), no live compute. Org dropped 15→13 projects.
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/complianceexposes 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/complianceprovides 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.
- 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
From2026-05-01_KANBAN_TO_PROD_FLOW.md. This is how a work item moves from “filed” to “deployed and verified”:
5.2 Tier paths (exhaustive)
| Tier | Paths that match | Who merges |
|---|---|---|
| Green | docs/**, *.md, session/**, documents/**, .github/ISSUE_TEMPLATE/** | Supervisor on blessed template; else CODEOWNER |
| Yellow | apps/*/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 change | CODEOWNER, always |
5.3 CODEOWNERS (target state after MA-4)
5.4 Canary + rollback protocol
Every production deploy runs_app-prod-canary.yml:
- Deploy new version to 10% of traffic (or equivalent for single-worker apps: deploy, then curl
/health+ key routes). - Watch Sentry for new issues + error-rate spike over baseline (default 30 min).
- If clean: promote to 100% (no-op for single-worker pattern).
- If spike: auto-rollback via
wrangler rollback <prior_deployment_id>+ Pushover alert.
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 needsmerge_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 labeldecision: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.mdwith the resolved outcome.
6.2 ADRs
Non-trivial design decisions get an ADR atdocs/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 editsmemory/*.md at a time. Running two Saunas in parallel writing memory creates races.
Mechanical enforcement (shipped in MA-8):
-
supervisor-loop.ymlconcurrency 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. -
memory-single-writer.ymlPR check — blocks any PR that editsmemory/*.mdwhen another open PR already has pending memory edits. Posts a blocking comment identifying the conflicting PR(s) and fails the required status check. -
CODEOWNERSmemory/**entry — pins@adrper79-dotas sole required reviewer for allmemory/changes, so the branch-protection review gate fires on every memory write regardless of tier.
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:- Decide strategic tier (revenue-facing, utility, etc.) and supervisor access level (none / Green / Yellow).
- Use
scripts/scaffold.mjsin factory to create the repo underLatimer-Woods-Tech. - Apply the standard ruleset via
setup-all-apps.mjs(branch protection, required checks). - Add CODEOWNERS matching §5.3 tier paths, adjusted for this app’s specific Red-tier paths.
- Add caller workflows pointing at
_app-ci.yml,_app-deploy.yml,_post-deploy-verify.yml,_app-reliability-gate.yml,_app-prod-canary.yml. - Provision Neon project in Adrian org; create production branch; wire Hyperdrive binding in
wrangler.jsonc. - Create Sentry project + DSN org secret.
- Add row to
docs/service-registry.ymlwith base_url, consumers, supervisor access. - Add
capabilities.ymlat repo root declaring every/adminroute the supervisor can call. Strict slot typing.side_effectsper route. - Add to this document’s §2.1 portfolio table.
- File tracking epic on LatWood Operations board linking back to §2.
main.
8. Playbook: ship a new version of a shared package
- Create a branch
feat/<package>-<summary>in factory. - Edit the package under
packages/<name>/. - Run
pnpm -F @latimer-woods-tech/<name> build && pnpm -F @latimer-woods-tech/<name> testlocally. - Bump version in the package’s
package.json(semver: patch for fixes, minor for additive, major for breaking). - Update
CHANGELOG.mdin the package directory. - Open PR against factory
main. Label:priority:P1(or P0 for security), phase as appropriate. Include blast-radius list of consumer apps. - CI runs
_app-ci.yml+_app-reliability-gate.yml. - On merge: factory’s
publish.ymlworkflow tags the package and publishes toregistry.npmjs.org. - Renovate opens PRs in every consumer app to bump the pinned version.
- Review consumer bumps per app (Red on packages; humans merge).
- For breaking changes (major bump): write a migration guide in
docs/packages/<name>/MIGRATION-<prev>-to-<new>.md.
9. Playbook: rotate a secret
Pick the kind:9.a GCP service-account key
- GCP console → IAM → Service Accounts → select SA → Keys → Add Key → Create new key (JSON). Download securely.
- Map downstream consumers:
grep -r "factory-sa\|supervisor-sa" ~/code/+ checkwrangler secret liston every worker. - Update every consumer (worker secrets via
wrangler secret put; GitHub Actions org secrets viagh secret set; Sauna stored connection via Settings UI). - Verify each consumer authenticates with the new key (whoami-style call per service).
- GCP console → revoke the old key.
- Document the rotation in
docs/runbooks/secret-rotation.mdwith 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)
- Mint new PAT via
https://github.com/settings/tokenswith the needed scopes (usuallyrepo+workflow+read:org+write:packages+project). - Update Sauna stored connection
conn_pvMtrQjxhkoZvia Settings UI (or replace if UI blocks edit). - Update
GH_PATorg secret viagh secret set GH_PAT --org Latimer-Woods-Tech. - Revoke old PAT.
9.d Cloudflare API Token
- Cloudflare dashboard → My Profile → API Tokens → Create similar token with the same permissions.
- Update
conn_nud8DHhsDiduvia Sauna Settings. - Update
CLOUDFLARE_API_TOKENorg secret. - 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 viawrangler 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
- Pushover fires with the issue short-id + link.
- Open Sentry → issue →
events/latest/. Capture: culprit, stack frames, recent tags, request URL, user count. - 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.
- Determine blast radius: single user? Single route? All requests?
- Decide:
- Transient (third-party outage, one-off): resolve as
auto-resolvedwith 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-modefeature flag if available; post user-facing status if customer-visible.
- Transient (third-party outage, one-off): resolve as
- If user impact is > 10 users OR revenue-critical: consider rolling back (
wrangler rollback <prior_sha>) while investigating. - 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 likecolumn <x> does not exist or relation <y> does not exist.
- 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. - Connect to the app’s production Neon via the direct connection string from the Neon dashboard.
- Query
information_schema.columns(or.tables) to confirm what’s actually in prod. - Read the migration tracking table:
SELECT * FROM drizzle.__drizzle_migrations ORDER BY id(or wherever the runner puts it). - Compute the gap: repo latest migration number minus prod applied. Apply missing migrations in order via
psql -fOR via the repo’snpm run migrate. - Verify the Sentry error stops firing within 2 hours.
- File or update SUP-1.4 (migration-drift-guard) so this never happens silently again.
file://session/hd-65-migration-runbook.md.
12. Playbook: author a supervisor template
Write templates reactively (from real closed issues), not proactively from imagination.- Pick a closed Red-tier or Yellow-tier issue that took the human < 2 hours and had a clear shape.
- Read the merged PR diff + commit trail. What files changed? What API calls happened in workflow logs?
- Draft
docs/supervisor/plans/<slug>.ymlfollowingdocs/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
- Create a fixture at
tests/supervisor/fixtures/<slug>.yml(a sample issue that should match). - Open PR.
template-suite.ymlruns match + parameterize + gates against the fixture; must pass. - Review with a CODEOWNER. Template starts unblessed. After 3 clean runs in prod (0 reverts, 0 overrides), it auto-blesses.
13. Playbook: resolve an open decision
- Open
docs/supervisor/DECISIONS.mdand find the decision row. - Click through to the linked issue (#110, #111, #112, etc.).
- Read the context + options + recommendation.
- 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.
- Merge the resolution PR. Downstream work (typically a phase exit gate) unblocks.
14. Playbook: onboard a new agent
14.a Human CODEOWNER
- Grant repo write access under
Latimer-Woods-Tech. - Add to
CODEOWNERSon paths they’ll own. - Have them read
docs/supervisor/FRIDGE.md(5 minutes) and this document’s §1 + §4 + §5 (another 15). - Pair on one Red-tier PR review before they solo.
14.b Second Sauna instance (parallel worker)
- MA-8 (memory single-writer) is mechanically enforced:
memory-single-writer.ymlblocks any PR that editsmemory/*.mdwhile another PR already has pending memory edits. The second Sauna must treatmemory/*.mdas read-only and propose edits as PRs. - Agent claims issues via
agent:claimed:sauna-2label (or similar discriminator). - Same fridge rules apply.
- Coordinate via issue comments, not via shared memory.
14.c Third-party autonomous agent (e.g., Copilot)
- Give it access scoped to Green-list paths only.
- Its commits must carry a trailer identifying the agent for audit traceability.
- If it’s App-authenticated: verify the App’s signed-commit requirement matches what the ruleset expects.
- 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:docs/supervisor/DECISIONS.mdfor founder-blocked decisions.- Open GitHub issues carrying
status:blocked,priority:*, and ownership labels for executable work. docs/STATE.mdanddocs/service-registry.ymlfor generated and deployed facts.- Docs Health and service-registry validation for detected drift.
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_kwDOEL0sNc4BWWtg — https://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 Tokenconn_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.
- Fridge —
docs/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 booleanmutating. - Source-trust label —
supervisor: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.
17.c Related documents (canonical map)
| Doc | Scope | Status |
|---|---|---|
This document (docs/architecture/FACTORY_V1.md) | Whole system + playbooks | Canonical, v1 |
docs/supervisor/ARCHITECTURE.md (v2.1) | Supervisor control plane deep dive | Authoritative for §3.4 |
docs/supervisor/FRIDGE.md | Operating rules | Overrides everything |
docs/supervisor/DECISIONS.md | Open + resolved decisions | Living; updated per decision |
docs/supervisor/EXECUTION_TRACKER.md | Phase-by-phase status | Mirror of LatWood Operations |
docs/supervisor/TEMPLATE_SPEC.md | Template schema + authoring rules | Deep-dive for §12 |
docs/supervisor/TEMPLATE_BOOTSTRAP_CANDIDATES.md | PR-history analysis for template seeding | SUP-3.3 input |
docs/CAPABILITY_CONTRACT.md | capabilities.yml schema | Deep-dive for §3 / §7 |
docs/service-registry.yml | Canonical service → URL → consumer map | Source of truth |
docs/ARCHITECTURAL_DECISION_RECORDS.md | ADR template + process | How to add an ADR |
docs/adr/NNNN-*.md | Individual ADRs | Immutable once Accepted |
docs/AGENTS.md | Agent operating rules for this repo | Complements FRIDGE |
CLAUDE.md | Standing orders for LLM agents | Complements FRIDGE |
factory_core_architecture.md | Historical: Phase 5 package spec | Superseded by §3.2 |
STAGE_6_ONWARDS_PLAN.md | Historical: Phase 6+ plan | Superseded by §3 + §16 |
FACTORY_STRATEGIC_REVIEW.md | Historical: April strategic assessment | Superseded by this doc |
2026-05-01_KANBAN_TO_PROD_FLOW.md | Historical: 9-step flow description | Retained; referenced by §5.1 |
2026-05-01_MULTI_AGENT_READINESS.md | Historical: MA-0 gap closure plan | Retained; MA-0 now mostly closed |
AI_CORE_AUDIT.md | Historical: LLM vendor audit | Decision 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
- Open a PR updating
docs/architecture/FACTORY_V1.mdon factory. - Label
documentation+priority:P1. - If the change resolves an open decision, also update
docs/supervisor/DECISIONS.mdin the same PR. - If the change conflicts with FRIDGE rules, stop and open an ADR first (FRIDGE revisions require ADRs).
- CODEOWNER review required (Red-tier path by default).