ADR-063: SDD Level 1 + stoa-impact MCP knowledge agent
- Status: Accepted (trial window, review 2026-04-30)
- Date: 2026-04-16
- Deciders: Christophe, Claude Code
- Relates to: ADR-061 (Council multi-stage review), ADR-062 (CLAUDE.md hierarchy)
- Parent ticket: CAB-2066 (split from CAB-2059 after Council S1bis 8.00/10)
Contextβ
Two operational gaps slowed MEGA execution through Q1 2026:
- No shared spec surface for MEGAs. Acceptance criteria, sub-tasks, and
dependency order were scattered across Linear comments,
plan.md, commit messages, and ad-hoc docs. Resuming a MEGA mid-flight required reading five places to reconstruct "what is done, what is next, when is it done." - Impact DB accessible only via shell.
docs/stoa-impact.dbcarries the dependency DAG, contracts, scenarios, and risks β but the only consumers weredocs/scripts/*.sh. Subagents without Bash permission (the default forsecurity-reviewer,docs-writer,content-reviewer,competitive-analyst,verify-app,k8s-ops) could not use it, so they fell back togrepand missed structured relationships.
Spec-Driven Development (SDD) has three well-known levels of adoption:
- L1 β structure only. A convention + templates, no tooling enforcement.
- L2 β spec-anchored. CI lints code against the spec.
- L3 β spec-as-source. Codegen from spec.
Both github/spec-kit (v0.7.1, MIT, 88K stars) and gotalab/cc-sdd (v3.0.2, MIT, 3K stars) target L2βL3 use cases but can be mined for L1 templates alone.
Decisionβ
1. Adopt SDD Level 1 onlyβ
- Add a lightweight
.sdlc/convention at the repo root:context/(architecture + conventions pointers, no duplication ofCLAUDE.md),templates/(requirement + task),specs/(one directory per formalized MEGA). - Pin cc-sdd v3.0.2 as the template inspiration. Borrow the frontmatter
state-machine (
pending β in_progress β done) from it. Do not install the CLI. STOA is Claude-Code-only; the CLI's multi-agent surface is unused. - Opt-in per MEGA. A MEGA without a
.sdlc/specs/MEGA-<ID>/entry is still valid. Adoption is measured over two weeks.
2. Expose stoa-impact.db via a local MCP serverβ
- New file:
docs/scripts/stoa_impact_mcp.py. - Pure Python stdlib (no
@modelcontextprotocol/sdkdep) β matches the existing "manual JSON-RPC protocol" pattern used byhegemon-mcpandstoa-gateway, and keeps the server trivially runnable on any dev machine with Python 3.11+. - JSON-RPC 2.0 over stdio (not HTTP/SSE) β aligns with the invocation
model already used by
linear,playwright, andcontext7in.mcp.json. - Read-only by construction:
sqlite3.connect("file:...?mode=ro", uri=True). Writes fail at the driver layer, not at the application layer. Validated by a regression test. - No raw-SQL tool. Eight purpose-built tools with parameterized queries
and
additionalProperties: falseon every input schema:list_components,get_componentget_contracts(direction: in / out / both)get_impacted_scenarios,get_risksget_dependency_matrix,get_untyped_contracts,get_component_risk_score
- Register in
.mcp.jsonas a localcommand: python3entry.
3. Kill-criteriaβ
The L1 convention and the MCP server ship together but are evaluated
independently on 2026-04-30. Kill triggers are recorded in
.sdlc/KILL-CRITERIA.md in the stoa repo:
- Zero real MEGA (excluding the dogfood CAB-2066 spec) formalized in
.sdlc/specs/within 14 days. - Spec drift: a shipped MEGA whose
.sdlc/entry no longer matches Linear or the merged code, with no reconciling commit. - Two distinct contributor complaints about duplication.
- MEGA cycle-time regression > +10% over the trial window.
If any trigger fires, .sdlc/ is removed in one commit and this ADR is
marked Superseded / Rejected with a post-mortem note.
For the MCP server, a separate kill signal: if the server causes CI churn
(flaky tests, perf regression in build-context.sh-based hooks) or if the
delta vs impact-check.sh turns out to be < 5Γ ergonomic improvement for
non-Bash subagents, remove the .mcp.json entry and delete the module.
Rationaleβ
- L1 before L2. We have no data that formalized specs are worth the write cost for this team. Starting at L2 (spec-anchored CI) risks locking in a convention nobody uses.
- Templates over tooling.
cc-sddandspec-kitboth assume an@agentCLI surface. STOA already has a standardized Claude Code entry point; adding a second CLI layer would fragment muscle memory. - cc-sdd over spec-kit. spec-kit is larger (88K stars) and Microsoft-backed, but targets multi-agent codegen (L2βL3). cc-sdd is smaller, Claude-native, and its template frontmatter is closer to what we need for L1. Both are MIT; licensing is a wash.
- MCP over shell for subagents.
impact-check.shtakes ~30ms; equivalent MCP calls take ~40ms. Latency is a non-factor. The real win is that subagents without Bash (security-reviewer, docs-writer, content-reviewer) can now use the impact graph. The delta is not performance β it is reach. - Pure stdlib server. The official
mcpPython SDK exists but is not already in use. Adding a dep for a ~400-line local tool is not worth it. The JSON-RPC 2.0 surface the spec requires is trivial to hand-roll and has better cache/startup behavior than an SDK-wrapped server. - No write-path MCP tool. The impact DB has one writer
(
populate-db.py) and an append-only learning script (post-change-learn.sh). Exposing any write surface via MCP would break that invariant and open the door to LLM-authored schema drift. Hard no.
Consequencesβ
Positiveβ
- Subagents gain structured impact queries. Security and docs reviews
now cite component + scenario relationships instead of eyeballing
grepoutput. - Spec dogfood. CAB-2066 itself is the first formalized MEGA under
.sdlc/specs/MEGA-CAB-2066/β four tasks with a state machine. - No net new deps. The server is stdlib-only; the convention is markdown-only.
- Kill path is cheap. Removing
.sdlc/or the MCP entry is a single-commit operation with no runtime-infra impact.
Negative / risksβ
- Documentation debt if unused. If the convention dies, the four template files and the kill-criteria are dead weight for the ~2-week trial window. Mitigated by the hard review date.
- MCP error messages are now opaque. Per the security review, SQL-layer errors are logged to stderr and replaced with generic client strings. Debugging a malformed query now requires reading the MCP server's stderr, not the tool call output. Acceptable for a local tool.
- Python 3.11+ required on any machine that wants to use the MCP
server. Already the baseline for
cli/andcontrol-plane-api/, so no new constraint.
Alternatives consideredβ
A. Adopt spec-kit fully (L2)β
- Install
specifyCLI, run spec-anchored checks in CI. - Rejected. No evidence teammates write specs first today; L2 locks in an unvalidated habit. Revisit after L1 trial.
B. Pure Python MCP SDK (mcp on PyPI)β
- Use the official SDK for schema + transport.
- Rejected. Adds a dep for < 200 non-SDK LOC. Dep churn risk. The
SDK also defaults to HTTP/SSE, which doesn't match the stdio-based
local-server pattern already in
.mcp.json.
C. Rust MCP server matching hegemon-mcp patternβ
- Match the existing Rust Axum custom-protocol pattern for consistency.
- Rejected.
hegemon-mcpuses HTTP/SSE for cross-service access; this tool is stdio-local. Rewriting in Rust for consistency doubles the implementation effort with zero user-visible benefit.
D. Expose the DB as a read-only endpoint on the gatewayβ
- Add a gateway route that serves the DB as JSON.
- Rejected. The impact DB is a dev-time artifact. Exposing it through a production-path gateway conflates two very different operational tiers.
E. Skip the MCP entirely β add more docs/scripts/*.shβ
- Write more shell wrappers for common queries.
- Rejected. Does not unlock non-Bash subagents, which was the motivating constraint.
Reviewβ
- Review date: 2026-04-30.
- Owner: @PotoMitan.
- Artifacts to inspect:
.sdlc/specs/(count of real MEGAs formalized),.mcp.json(still present?), grep forstoa_impact_mcpcalls in session logs (usage signal), Linear cycle-time dashboard.
Referencesβ
- Linear MEGA: CAB-2066
- Parent Council validation: CAB-2059 S1bis 8.00/10
- Unblocked by: CAB-2065 (Agent Teams canary Go, 2026-04-16)
- Repo artifacts:
.sdlc/,docs/scripts/stoa_impact_mcp.py,.mcp.json - Related ADRs: ADR-061 (Council multi-stage), ADR-062 (CLAUDE.md hierarchy)