Captures the design from the brainstorm session on agent-first development in this template. Architecture doc covers the four interlocking pillars: - Conformance engine (manifest + brands + ESLint + boot + CI gate) - Agent workflow (PRD -> Epic -> Story -> Task; manifest-first ordering; TDD per slice; in/out scope at every level) - Local task system at docs/work/ (filesystem markdown, derived committed _state.json, single-writer orchestrator rule) - Sandcastle orchestrator (implementer + reviewer loop, DAG-respecting, configurable retry cap) Work-shape guides extend the architecture doc with operational detail for frontend work (atomic design, Storybook-as-spec, component + Playwright screenshot test gates, Storybook MCP reviewer integration) and infrastructure work (ADR-first flow, dedicated ADR elicitation skill, optional core packages vs. new infrastructure layers). Phasing is conformance-first: build the enforcement system manually, then build the dispatch substrate, then migrate remaining features through it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
155 lines
7.2 KiB
Markdown
155 lines
7.2 KiB
Markdown
# 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 <name>` |
|
|
| **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-<slug>.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 "<one-line proposal>"`
|
|
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-<slug>.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: <decision 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 <name>` — generator emits canonical shape
|
|
3. Implement package contents (interface, impls, tests) — flows through normal story-and-task decomposition
|
|
4. Add `<name>` 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: ["<name>"]` 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 <name>` 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?
|