# Infrastructure work shape How infrastructure work — new core packages, new external services, new database backends, new build/deploy primitives — flows through the agent-first workflow. For the broader workflow context see [`docs/architecture/agent-first-workflow-and-conformance.md`](../architecture/agent-first-workflow-and-conformance.md). ## When this guide applies You're proposing or implementing: - A new optional core package (`core-cache`, `core-email`, `core-feature-flags`, …) - A new external service or layer (Redis, CDN, alternative CMS, additional message bus, …) - A change to bootstrap, build, or CI infrastructure - A swap of an existing infrastructure component If you're working on backend feature code or frontend, this is not your guide. ## Two categories | Category | Example | Path | |---|---|---| | **A. New optional core package** | `core-cache`, `core-email` | `pnpm turbo gen core-package ` | | **B. New infrastructure layer** | Redis, CDN, deploy target, CI image swap | ADR → integration PRD → epic + stories | Category A is well-trodden: the generator emits a canonical core-package shape; the conformance system already handles optional cores via `requiredCores` in manifests. No new conformance rules required. Category B is the one that needs the ADR-first dance described below. ## ADRs precede infrastructure work ADRs (Architecture Decision Records) live at `docs/adr/NNN-.md`. The pattern is established in this repo (ADR-018 captured the audit-and-compliance system, for example). ADRs are to infrastructure what PRDs are to features: decision documents, written first, providing the rationale that downstream PRDs and stories implement. An ADR documents *what was decided and why*; a PRD documents *what to build*. ## ADR authoring flow ``` 1. Human runs `pnpm work adr-new ""` 2. Dedicated ADR elicitation skill interviews the human: - Context (what's the situation today?) - Drivers (what's forcing a decision?) - Considered options (what alternatives are on the table?) - Trade-offs (what does each option cost?) - Decision (which option, and why?) - Consequences (what changes downstream?) 3. Agent drafts ADR at docs/adr/NNN-.md with status: proposed 4. Human reviews, edits, flips to status: accepted (or rejected / superseded) 5. Accepted ADR(s) trigger one or more integration PRDs 6. PRDs flow through the normal decompose → dispatch loop ``` The ADR elicitation skill is distinct from the PRD elicitation skill. Same interview shape, different template and pushiness: - PRD eliciter focuses on **problem framing** and **success criteria** - ADR eliciter focuses on **alternatives** and **trade-offs** — it actively pushes back if only one option is articulated ## ADR template ```markdown --- id: NNN title: status: proposed | accepted | rejected | superseded date: YYYY-MM-DD supersedes: [] superseded-by: null related-prds: [] --- ## Context What's the situation? What's broken or about to break? Who is affected? ## Drivers What's forcing this decision now? ## Considered options - Option 1: ... - Pros / Cons - Option 2: ... - Pros / Cons - Option 3: ... - Pros / Cons ## Decision We chose Option X because ... ## Consequences ### Positive - ... ### Negative / accepted trade-offs - ... ### Follow-up work - PRD: ... - PRD: ... ``` ## Path A: new optional core package When the new infrastructure is *small enough to be a single package* (cache, email, feature flags, etc.): 1. ADR (if the decision is non-trivial — for "add core-cache because we need response caching", a short ADR is still worthwhile) 2. `pnpm turbo gen core-package ` — generator emits canonical shape 3. Implement package contents (interface, impls, tests) — flows through normal story-and-task decomposition 4. Add `` to manifests' `requiredCores` in features that adopt it 5. Wire into `BindContext` in `core-shared/di/` 6. Wire into each app's `bindAll()` aggregator 7. Update generator templates if features need to scaffold differently when this core is present (e.g., `core-events` causes `turbo gen feature` to emit event-handler stubs) The conformance system catches forgotten wiring automatically: - `required-cores-installed` ESLint rule flags manifests declaring `requiredCores: [""]` when the package isn't in `pnpm-workspace.yaml` - Boot assertion `assertConformance(ctx)` fails on missing bind-context entries - CI's `pnpm conformance` aggregates the cross-feature view ## Path B: new infrastructure layer When the new infrastructure is bigger than one package — a new external service, a swap of an existing component, a deploy-target change: 1. **ADR** captures the decision and trade-offs 2. **Integration PRD(s)** specify what to build/wire/migrate; one PRD per integration concern is common 3. PRDs decompose into the normal Epic → Story → Task hierarchy 4. Stories typically include: a new core package (if one fits), configuration plumbing, bootstrap wiring, feature adoption, documentation updates, and (often) a deprecation/removal of the prior approach Examples of category B work: - "Add Redis for response caching" — ADR + core-cache package + bind-context wiring + adoption stories per feature - "Replace Payload with Sanity" — ADR + repository implementation swap + migration scripts + docs rewrite - "Move from Vercel to Cloudflare Workers" — ADR + new deploy target stories per app + CI workflow updates ## Conformance for infrastructure Two rules extend the conformance system for infra concerns: | Rule | Layer | What it catches | |---|---|---| | `required-cores-in-workspace` | ESLint + CI | manifest declares a core that isn't in `pnpm-workspace.yaml` | | `core-package-shape-conforms-to-generator` | CI | a core package's structure has drifted from what `pnpm turbo gen core-package ` would produce today | These extend the existing milestone iv work; no new tooling required. ## Common pitfalls - **Skipping the ADR for "small" infra changes.** A swap of a single dependency is still a decision worth recording. The ADR doesn't have to be long — but it should exist. - **Implementing before the ADR is accepted.** Don't decompose an integration PRD into stories until the ADR is `accepted`. The work-system orchestrator can refuse to dispatch tasks whose epic's ADR is still `proposed`. - **Manifest drift after infra adoption.** A new core is added but features that use it don't declare it in `requiredCores`. The ESLint rule catches the inverse (declared-but-not-installed); CI's full conformance run also checks the other direction. - **Bootstrap wiring forgotten.** A new core package is created but never bound in `apps/*/server/bind-production.ts`. Boot assertion catches this on first `pnpm dev`. - **Documentation lag.** New infra is shipped but `docs/guides/` and `CLAUDE.md` aren't updated. Make documentation a required story under any integration epic. ## Open items (filled in as we ship) - ADR elicitation skill — exact prompt shape and heuristics - ADR ↔ PRD linkage — how an accepted ADR fans out into one or more PRDs (frontmatter `related-prds`?) - Refusal logic — should the work-system refuse to decompose a PRD whose triggering ADR is still proposed?