eng-flow architecture
Stage 3 of the production track. Everything Stage 1 and Stage 2 deferred — tech stack, system diagram, API shape, quantified NFRs, deployment — gets decided here. This is the one production stage where technical questions are not just allowed but the entire point.
Analytics
At the start of every numbered step below (including Step 0), run python3 "${CLAUDE_PLUGIN_ROOT}/.claude/skills/lib/bin/eng-flow-analytics-checkpoint" eng-flow-architecture "<step name>" "<dated-slug>". As the last action of Step 10, run python3 "${CLAUDE_PLUGIN_ROOT}/.claude/skills/lib/bin/eng-flow-analytics-finish" eng-flow-architecture "<dated-slug>". See eng-flow-spec's Analytics section for what this logs and why; rollup via eng-flow-analytics (Stage 10).
Decision Ledger
Check $ARGUMENTS for a --guide token; if present, every decision point below gets an explicit AskUserQuestion instead of a silent default, and Step 10's report adds a "Decisions I made / decisions you made" summary. Log every decision point via python3 "${CLAUDE_PLUGIN_ROOT}/.claude/skills/lib/bin/eng-flow-decision-log" eng-flow-architecture "<step>" <reason> <mode> <owner> "<description>" "<dated-slug>". See eng-flow-spec's Decision Ledger section for the taxonomy and why. Rollup/analysis: eng-flow-retro Step 1 (Stage 9).
Step 0 — Find the inputs
Look for eng-flow/specs/*/spec.md and the matching domain-model.md in the same folder. If more than one spec folder exists, ask which one this run is for.
If spec.md is missing: offer via AskUserQuestion — "No spec found for this. eng-flow-spec captures the problem, audience, and scope this stage needs to ground decisions in. Run it now?" Options: A) Run eng-flow-spec now (resume architecture right after) B) Cancel — I'll run it myself. If A, invoke eng-flow-spec with the Skill tool, then re-run this check once it saves. If B, stop here.
If spec.md exists but domain-model.md is missing: same offer, naming eng-flow-domain-model instead — its entities, relationships, and conceptual diagram are this step's other required input.
Read the spec's constraints (Phase 1, "what constraints came with the approval") and non-functional requirements, and the domain model's entities/relationships/conceptual diagram — these are the inputs to every step below.
Step 1 — Tech stack
If this extends an existing product, use its existing stack — don't relitigate it here. If greenfield, ask, constrained by anything the spec already locked in (e.g. "must use vendor X").
Apply boring by default: prefer proven, well-understood technology unless there's a specific, stated reason not to. If the user picks something novel/unproven, ask them to name the reason explicitly (it becomes part of the ADR in Step 7) — an unjustified novel choice is a flag to raise, not silently accept.
Log it: risk silent_decide ai_default "tech stack: reused existing / boring-by-default choice" if no relitigation was needed, otherwise risk open_question user_confirmed "tech stack: <choice> — reason: <stated reason>".
Step 2 — System diagram
Take Stage 2's conceptual diagram (domain boxes, no tech) and promote it to a container-level diagram (C4 model terminology: context → container → component → code; this stage stops at container, not component/code level): same domains, now labeled with the actual service/technology handling each. This is the one diagram in the whole track where tech labels belong.
Draft it as mermaid first — that's what goes in the saved file. Then ask once: "Want this rendered as a diagram you can actually see, or is the mermaid source in the saved file enough?" Default to skipping if the user doesn't ask. If yes, load the artifact-diagramming skill and publish via the Artifact tool; note the artifact URL alongside the saved diagram source in Step 8/9.
Log it: risk silent_decide ai_default "diagram rendering: skipped, mermaid source only" if the default applies, otherwise open_question user_confirmed.
Step 3 — Frontend/backend separation
Decide based on the actual complexity surfaced in Stage 2 — number of domains, their coupling, team size — not by default. If scope is small, say so and recommend staying monolithic; splitting into separate frontend/backend (or further into services) is a decision to justify, not a default to assume. If it does split, name the boundary explicitly (what runs where).
Log it: risk silent_decide ai_inferred "frontend/backend separation: <monolith|split> — <reasoning from Stage 2 complexity>".
Step 4 — API contracts
Define the interface between frontend/backend and between domains identified in Stage 2, contract-first — the contract is written before implementation, not derived from it.
Apply the same discipline agent-skills' api-and-interface-design documents:
- Hyrum's Law — every observable behavior becomes a de facto commitment once something depends on it; be deliberate about what's exposed, don't leak implementation details.
- Contract first — define request/response shapes before writing the implementation.
- One-Version Rule — design so consumers never have to choose between multiple versions of the same interface.
Depth matches scope — a small feature needs a short list of endpoint shapes, not a full OpenAPI spec, unless the scope actually warrants one.
Step 5 — Non-functional requirements (quantified)
Stage 1 captured NFRs at the business level ("fast," "secure," "available") — this step translates them into technical targets:
- Performance: response time / latency budget under what load
- Scale: concurrent users, data volume, growth assumptions
- Availability: uptime target
- Security: specific controls, not just "secure" (auth model, data-at-rest/in-transit handling)
- Compliance: specific standards if the spec named any
Ask for numbers if the spec didn't give any. If none are available and the user doesn't have a target in mind, state the assumption explicitly rather than inventing a number silently.
Log it: risk silent_decide ai_default "NFR target for <dimension>: assumed <value> — no user-provided number" for each assumed target — this is exactly the kind of silent default eng-flow-retro should be watching for correlation against later rework.
Project-level security policy. Look for eng-flow/security-policy.md — project-level, sits alongside design-system.md (reused across specs, not rebuilt per run). If it exists, the Security NFR above must address each of its stated rules explicitly for this spec's scope, not just restate "secure." If it doesn't exist, offer via AskUserQuestion: "No project-level security policy found. Establish standing rules now (e.g. credential handling, least-privilege data access, write confirmation) that this and future specs' architecture/eng-review/code-review stages will check against?" Options: A) Yes — capture rules now B) No — this spec's Security NFR stands alone. If A and the user has no strong opinion yet, offer common local-first defaults as a starting point (edit to taste): local/MCP servers never forward credentials off the local machine; DB access defaults to least-privilege/read-only unless a story states a write is required; secrets load from environment variables and never enter committed config; state-mutating operations require explicit confirmation before executing. Save the agreed rules as a short numbered list to eng-flow/security-policy.md. This is a knowledge-asymmetry call — never invent or silently skip project security policy.
Log it: risk knowledge_asymmetry open_question user_confirmed "security policy: established — N rules | declined | already existed".
Step 6 — Deployment
Default to what the user actually does, not an assumed cloud target: local development, containers, GitHub (per the project's real practice) — document that as the deployment topology (dev/staging/prod environments, or fewer if that's the real setup), the CI pipeline (GitHub Actions or equivalent), and any infrastructure-as-code in use.
Add a short cloud-ready notes subsection: what would need to change to deploy this to a cloud target later (which components would need it, roughly what'd be involved) — informational, not a decision to act on now. This is what makes the doc useful to another engineer picking this up later without forcing a cloud decision that isn't warranted yet.
Log it: risk silent_decide ai_inferred "deployment topology: matched actual practice (<local/containers/GitHub>)".
Step 7 — ADRs
Reuse agent-skills' convention rule: before creating an ADR, check for an existing convention in the repo (an adr/ or docs/decisions/ directory, an .adr-dir file, existing numbered ADRs) and match its location, numbering, and section headings. Only apply the default below if no convention exists.
Write one ADR per decision from Steps 1-6 that would be expensive to reverse — framework/library choice, data model, auth strategy, API architecture style, deployment/hosting choice. Not every small choice needs one; a Step 1 "boring by default" pick with an obvious reason usually doesn't.
Log it: risk silent_decide ai_inferred "ADR convention: <matched existing repo convention | applied default location/numbering>".
Default (no existing convention found): eng-flow/specs/<dated-slug>/adr/NNNN-title.md, sequential numbering starting at 0001:
# ADR-NNNN: [Decision]
## Status
Accepted
## Context
[What problem/question this decision answers]
## Decision
[What was chosen]
## Alternatives Considered
[What else was on the table, and why not]
## Consequences
[What this makes easier, harder, or forecloses]
Step 8 — Draft and confirm
# Architecture: [Name]
(source: spec.md, domain-model.md in this folder)
## Tech Stack
[Choices + justification, especially anything not "boring by default"]
## System Diagram
[Container-level, domains from Stage 2 now tech-labeled]
[Artifact URL, if rendered; omit line otherwise]
## Frontend/Backend Separation
[Decision + reasoning — or "staying monolithic, and why"]
## API Contracts
[Endpoint/interface shapes]
## Non-Functional Requirements
[Quantified targets per Step 5]
## Deployment
[Topology, CI pipeline, IaC — actual current practice]
[Cloud-ready notes]
## ADRs
[List of ADR files written in Step 7, or "none warranted" if genuinely none]
Show the draft, ask: "Does this match what you'd actually build, or anything to change?" Log it: risk open_question <user_confirmed|user_revised> "draft accepted|draft revised: <what changed>".
Step 9 — Save
Write architecture.md to the same spec folder (eng-flow/specs/<dated-slug>/architecture.md), and any ADR files to eng-flow/specs/<dated-slug>/adr/ (or the matched existing convention's location).
Step 10 — Report back
Confirm the saved paths. Tell the user this feeds Stage 4 (epics/stories/tasks — breaking this into executable work), not yet run.
If this run was in guide mode, add a "Decisions I made / decisions you made" summary here, drawn from this run's eng-flow-decision-log calls.
Run the Step 10 analytics-finish call (see Analytics section above) before ending.