Architecture
Turns requirements into a concrete system shape — components, boundaries, data flow, failure modes, and technology choices. This is the thinking skill: it's about decomposition and trade-offs, not about writing the document (that's documentation:write-design-doc when installed), modeling data (that's data-modeling), or designing APIs (that's api-design).
Current context
- Project: !
basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "(not a git repo)"
- Existing architecture artifacts: !
ls .context/architecture/ 2>/dev/null || echo "none yet"
Decision tree
- What does the user need?
- Designing a new system from scratch → run the full process below
- Adding a new feature or service to an existing system → read existing
.context/ first, scope the work to the new slice only
- Rough sketch or whiteboard discussion → talk through components and trade-offs in chat, skip the formal output
- User already has requirements documented → read them, proceed to decomposition
- User doesn't have clear requirements yet → hand off to
planning:requirements first when available
- User wants a picture → hand off to
workflow:c4-diagrams when available
- User wants to capture a specific decision → hand off to
documentation:write-adr when available
Philosophy
These principles come from references/philosophy.md and apply to every architecture decision:
- Monolith-first. Split only when forced by real operational or scaling pain — not because a diagram looks cleaner with more boxes. Distributed systems are harder to debug, deploy, and reason about.
- Extract early when the concept is clear. If a bounded context is obvious today, draw the boundary now. Don't wait for rule-of-three — waiting creates coupling that's expensive to undo.
- Lean on existing stack hard. Every new tool is a new failure mode, a new thing to monitor, a new thing to learn. Deviate when the existing stack genuinely can't do the job, not when a shinier option exists.
Full process
1. Component decomposition
Identify the bounded contexts — the natural seams in the system where one responsibility ends and another begins.
- Each component gets exactly one responsibility, stated in a single sentence.
- If two components share a database, ask whether they should be one component — shared storage is a hidden coupling.
- If one component touches everything, ask whether it should be split — that's a "god service" in disguise.
- Name each component clearly. A name like "processor" or "handler" is a smell; "order-fulfillment" or "payment-gateway" tells you what it does.
- Prefer fewer components with clear boundaries over many small ones with unclear boundaries. Each boundary is a maintenance cost — make sure it earns its keep.
2. Data flow analysis
Trace 2-3 representative requests through the system end-to-end. Pick flows that exercise different paths: a happy-path read, a write with side effects, and an error case.
For each hop between components:
- Is it synchronous (HTTP call, gRPC) or async (queue, event)?
- What protocol does it use?
- What's the latency budget for this hop?
Identify the hot path — the flow that handles the most traffic or is most latency-sensitive. Optimize the hot path first; everything else can be "good enough."
Mark where work is inline (must complete within the request, <50ms) vs queued (can happen later via CF Queues or similar). Queuing is the cheapest way to make a system feel fast — if the user doesn't need the result right now, don't make them wait.
3. State ownership
- Which component owns which data? Exactly one source of truth per piece of data. If two components both write to the same field, you have a bug waiting to happen.
- Where are caches? How do they invalidate? Stale caches are the #1 source of "it works sometimes" bugs.
- What's the consistency model? Strong consistency within a single service (same DB transaction). Eventual consistency across services (events, queues). Be explicit about which you're choosing and why.
4. Failure mode thinking
For each component, answer:
- What happens when it's slow? Do callers time out? Do queues back up? Does the user see a spinner forever?
- What happens when it's down? What else breaks? This is the blast radius.
- What happens when it returns garbage? Can callers validate responses, or do they trust blindly?
- Can the system degrade gracefully? Read-only mode, cached fallbacks, queued writes for later replay — these are the difference between "outage" and "degraded."
- Are timeouts set everywhere? An HTTP call without a timeout is a thread leak waiting to happen.
- Are retries bounded? Unbounded retries turn a blip into a thundering herd.
5. Tech selection
Lean on the reference files (references/async.md, references/resilience.md, references/deploy.md, references/third-party.md) for all infrastructure choices. For the data store decision (D1 vs Neon), see data-modeling's "Data store selection" section — the short version: D1 for small/simple, Neon for multi-tenant/complex/compliance. For each technology decision:
- What does this buy us? Be specific — "Postgres gives us ACID transactions across these three tables in a single commit."
- What are we giving up? Every choice has a cost — operational complexity, vendor lock-in, learning curve.
- Does it match the existing stack? If deviating from conventions, say WHY clearly. Deviations are fine; silent deviations are tech debt.
6. Trade-off analysis
For each non-obvious decision, structure as:
| Decision |
Chose |
Rejected |
Why |
| Message passing |
CF Queues |
Kafka |
Queues integrates natively with Workers; Kafka adds ops burden for throughput we don't need |
| Session storage |
KV |
D1 |
Sessions are short-lived key-value lookups; KV is cheaper and faster for this access pattern |
Give rejected options their real best case — strawman comparisons are useless. If Kafka genuinely is better for high-throughput ordered streams, say so, then explain why that's not this situation. Tie each decision back to a specific requirement or constraint.
Cross-references
| When |
Use |
| Need to design the data model |
data-modeling |
| Need to design the API |
api-design |
| Need a diagram |
workflow:c4-diagrams if installed |
| Ready to write the doc |
documentation:write-design-doc if installed |
| A decision deserves recording |
documentation:write-adr if installed |
| Need to gather requirements first |
planning:requirements if installed |
Key references
| File |
Covers |
references/philosophy.md |
Monolith-first, extract early, lean on existing stack |
references/async.md |
Inline vs queue, cron, outbox pattern, realtime (SSE/WebSocket) |
references/resilience.md |
Timeouts, retries, circuit breakers, caching, service-to-service |
references/observability.md |
Logging, request IDs, metrics, tracing, alerting, access logs |
references/deploy.md |
Monorepo layout, deployment, secrets, config, health checks, local dev |
references/testing.md |
Test pyramid, Worker tests, DB testing, fixtures, mocking, E2E |
references/third-party.md |
Default vendors: email, payments, analytics, search, monitoring |
references/privacy.md |
Data residency, PII storage, GDPR deletion, cookie consent |
1---2name: architecture3description: Guides system architecture and decomposition — turns requirements into a concrete system shape by identifying components, drawing boundaries, tracing data flow, analyzing failure modes, and selecting technology. Covers the intellectual work of breaking a system apart, not the writing of a design document. Use when the user asks to architect a system, decompose a feature into components, figure out how services should talk to each other, evaluate system trade-offs, or says things like "how should we structure this", "what components do we need", "let's think through the architecture", or "where should this logic live".4---56# Architecture7Turns requirements into a concrete system shape — components, boundaries, data flow, failure modes, and technology choices. This is the thinking skill: it's about decomposition and trade-offs, not about writing the document (that's `documentation:write-design-doc` when installed), modeling data (that's `data-modeling`), or designing APIs (that's `api-design`).89## Current context10- Project: !`basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "(not a git repo)"`11- Existing architecture artifacts: !`ls .context/architecture/ 2>/dev/null || echo "none yet"`1213## Decision tree14- What does the user need?15 - **Designing a new system from scratch** → run the full process below16 - **Adding a new feature or service to an existing system** → read existing `.context/` first, scope the work to the new slice only17 - **Rough sketch or whiteboard discussion** → talk through components and trade-offs in chat, skip the formal output18 - **User already has requirements documented** → read them, proceed to decomposition19 - **User doesn't have clear requirements yet** → hand off to `planning:requirements` first when available20 - **User wants a picture** → hand off to `workflow:c4-diagrams` when available21 - **User wants to capture a specific decision** → hand off to `documentation:write-adr` when available2223## Philosophy24These principles come from `references/philosophy.md` and apply to every architecture decision:2526- **Monolith-first.** Split only when forced by real operational or scaling pain — not because a diagram looks cleaner with more boxes. Distributed systems are harder to debug, deploy, and reason about.27- **Extract early when the concept is clear.** If a bounded context is obvious today, draw the boundary now. Don't wait for rule-of-three — waiting creates coupling that's expensive to undo.28- **Lean on existing stack hard.** Every new tool is a new failure mode, a new thing to monitor, a new thing to learn. Deviate when the existing stack genuinely can't do the job, not when a shinier option exists.2930## Full process3132### 1. Component decomposition33Identify the bounded contexts — the natural seams in the system where one responsibility ends and another begins.3435- Each component gets exactly one responsibility, stated in a single sentence.36- If two components share a database, ask whether they should be one component — shared storage is a hidden coupling.37- If one component touches everything, ask whether it should be split — that's a "god service" in disguise.38- Name each component clearly. A name like "processor" or "handler" is a smell; "order-fulfillment" or "payment-gateway" tells you what it does.39- **Prefer fewer components with clear boundaries over many small ones with unclear boundaries.** Each boundary is a maintenance cost — make sure it earns its keep.4041### 2. Data flow analysis42Trace 2-3 representative requests through the system end-to-end. Pick flows that exercise different paths: a happy-path read, a write with side effects, and an error case.4344For each hop between components:4546- Is it **synchronous** (HTTP call, gRPC) or **async** (queue, event)?47- What **protocol** does it use?48- What's the **latency budget** for this hop?4950Identify the **hot path** — the flow that handles the most traffic or is most latency-sensitive. Optimize the hot path first; everything else can be "good enough."5152Mark where work is **inline** (must complete within the request, <50ms) vs **queued** (can happen later via CF Queues or similar). Queuing is the cheapest way to make a system feel fast — if the user doesn't need the result right now, don't make them wait.5354### 3. State ownership55- **Which component owns which data?** Exactly one source of truth per piece of data. If two components both write to the same field, you have a bug waiting to happen.56- **Where are caches?** How do they invalidate? Stale caches are the #1 source of "it works sometimes" bugs.57- **What's the consistency model?** Strong consistency within a single service (same DB transaction). Eventual consistency across services (events, queues). Be explicit about which you're choosing and why.5859### 4. Failure mode thinking60For each component, answer:6162- **What happens when it's slow?** Do callers time out? Do queues back up? Does the user see a spinner forever?63- **What happens when it's down?** What else breaks? This is the blast radius.64- **What happens when it returns garbage?** Can callers validate responses, or do they trust blindly?65- **Can the system degrade gracefully?** Read-only mode, cached fallbacks, queued writes for later replay — these are the difference between "outage" and "degraded."66- **Are timeouts set everywhere?** An HTTP call without a timeout is a thread leak waiting to happen.67- **Are retries bounded?** Unbounded retries turn a blip into a thundering herd.6869### 5. Tech selection70Lean on the reference files (`references/async.md`, `references/resilience.md`, `references/deploy.md`, `references/third-party.md`) for all infrastructure choices. For the data store decision (D1 vs Neon), see `data-modeling`'s "Data store selection" section — the short version: D1 for small/simple, Neon for multi-tenant/complex/compliance. For each technology decision:7172- **What does this buy us?** Be specific — "Postgres gives us ACID transactions across these three tables in a single commit."73- **What are we giving up?** Every choice has a cost — operational complexity, vendor lock-in, learning curve.74- **Does it match the existing stack?** If deviating from conventions, say WHY clearly. Deviations are fine; silent deviations are tech debt.7576### 6. Trade-off analysis77For each non-obvious decision, structure as:7879|Decision|Chose|Rejected|Why|80|---|---|---|---|81|Message passing|CF Queues|Kafka|Queues integrates natively with Workers; Kafka adds ops burden for throughput we don't need|82|Session storage|KV|D1|Sessions are short-lived key-value lookups; KV is cheaper and faster for this access pattern|8384Give rejected options their real best case — strawman comparisons are useless. If Kafka genuinely is better for high-throughput ordered streams, say so, then explain why that's not this situation. Tie each decision back to a specific requirement or constraint.8586## Cross-references87|When|Use|88|---|---|89|Need to design the data model|`data-modeling`|90|Need to design the API|`api-design`|91|Need a diagram|`workflow:c4-diagrams` if installed|92|Ready to write the doc|`documentation:write-design-doc` if installed|93|A decision deserves recording|`documentation:write-adr` if installed|94|Need to gather requirements first|`planning:requirements` if installed|9596## Key references97|File|Covers|98|---|---|99|`references/philosophy.md`|Monolith-first, extract early, lean on existing stack|100|`references/async.md`|Inline vs queue, cron, outbox pattern, realtime (SSE/WebSocket)|101|`references/resilience.md`|Timeouts, retries, circuit breakers, caching, service-to-service|102|`references/observability.md`|Logging, request IDs, metrics, tracing, alerting, access logs|103|`references/deploy.md`|Monorepo layout, deployment, secrets, config, health checks, local dev|104|`references/testing.md`|Test pyramid, Worker tests, DB testing, fixtures, mocking, E2E|105|`references/third-party.md`|Default vendors: email, payments, analytics, search, monitoring|106|`references/privacy.md`|Data residency, PII storage, GDPR deletion, cookie consent|