The Canonical Technology Stack
The instruction hierarchy (§4.1-4.4) tells AI agents what to read and which skills to invoke. The canonical tech stack tells them what to build with — methodology-level defaults that flow downstream into every project's CLAUDE.md and ADR-0001 instead of being re-derived per project.
In one line: A three-tier stack — mandatory / default / forbidden — so a fresh project starts at the right defaults from day zero and a contributor reads one document instead of three codebases.
What: The canonical tech stack lists the libraries, tools, and patterns S4U projects use across the board. Every project's ADR-0001 references it and either accepts the defaults or amends them with rationale. Three tiers, distinct semantics:
-
Mandatory. Always use this; deviating requires an ADR justifying why and what the alternative buys. Examples:
pydantic v2for validation,structlogfor structured logging (never stdlibloggingdirectly in app code),testcontainersfor integration tests,pytest-asynciomodeauto,pyrightfor static typing. The deviation bar is high because mandatory items are load-bearing for other guarantees — evidence-over-claims needs mechanically queryable structured logs; testcontainers is what makes the no-mocking-by-default rule (§7) enforceable. -
Default. Use unless you have a project-specific reason; the reason goes in ADR-0001. Examples:
httpxfor HTTP clients,respxfor HTTP testing,freezegunfor time-travel tests,asyncpgfor application Postgres queries,psycopg 3only when a dependency requires it,SQLAlchemy 2.0 async+Alembic. The deviation bar is moderate — right defaults, bounded swap cost. -
Forbidden. Never use, regardless of project. Examples:
time.sleep()in tests (use fake clocks); mocking-by-default (use testcontainers, §7); in-memory databases as test fixtures; therequestslibrary for new code (sync, not async-native);unittest.mockof internal classes (mock at process boundaries only, §5.4);alert()/confirm()/ native browser dialogs in UI (use toasts + inline UI, §UI/UX).
Why: Cross-project consistency compounds. Projects in different domains still overlap heavily in stack; where they overlap, contributors move between them without re-learning HTTP-testing patterns, logging conventions, or migration shapes. Without a rule, that consistency is encoded by osmosis — a contributor copies the previous project's pattern. Codifying it means day-zero defaults and one document instead of three codebases.
The three tiers are load-bearing. A flat "preferred stack" collapses the difference between "you must use structlog" (the rule that makes §2.3's evidence pattern tractable) and "reach for httpx first" (a defensible default). Mandatory items are requirements; defaults are opinions; forbidden items are guardrails — each with a different deviation cost.
Three load-bearing rules:
-
Single source, pointers elsewhere. Every normative rule — including the mandatory stack list — lives in exactly one loadable home (the operating card, a named skill, or appendix-m for the stack). A project's
CLAUDE.mdcarries a one-line pointer plus only genuinely project-specific deltas, each backed by a deviation ADR. Verbatim copies are forbidden: every contradiction pair observed in practice traced back to a hand-maintained copy that drifted. Drift is checked mechanically byscripts/check-canon-consistency.shin CI, not by human re-reading. What changed is only WHERE rules live — once, not four times. -
Deviation has an ADR cost proportional to the tier. Mandatory deviation: a new ADR in
docs/adr/justifying the departure. Default deviation: an entry in the existing ADR-0001 (no new ADR needed). Forbidden tier has no deviation path — the cost is "you can't ship that and still claim to follow the methodology." This proportionality is what gives the tiers teeth; without it, every choice slides toward "default" and the list loses enforcement value. -
The canonical stack is amended from real-project evidence, not speculation. A library moves from default to mandatory only after ≥2 projects have shipped with it for ≥3 months. It moves to forbidden only after ≥1 project hit a real failure mode the library caused (cited concretely in the appendix). New additions land in the default tier first; promotion/demotion happens by amendment. This prevents wishful-thinking entries nobody uses.
Evidence: The stack is curated from the union of multiple production projects, with an "inspired-from" pointer per entry so the lineage is auditable. Mandatory items are the ones shipped from day one across projects; defaults emerged as consensus; forbidden items are codified failures (the no-mocking rule, for instance, traces to a project losing days to mock/prod divergence). Reproducible: scripts/check-canon-consistency.sh fails CI if a project's copy drifts from the appendix. The full list — by category, with deviation-rationale templates — is in appendix-m-canonical-stack.md.
The canonical stack interacts with the rest of the methodology:
- Project ADR-0001 (tech stack) becomes a thin amendment on top of the canonical stack, not a from-scratch derivation. Most ADR-0001s become 1-2 pages instead of 5-10.
- §7 quality gates (no mocking, evidence-over-claims) are enforceable only because the mandatory tier guarantees the underlying primitives exist. structlog mandate makes "evidence is structured-log queries" a methodology rule rather than a project preference.
- §5.6 product-scale planning includes a step "verify each milestone's ADRs reference the canonical stack" — drift between methodology canon and project ADR-0001 is a cross-consistency review issue.