blueprint-index
v0.2.0Living architecture map for brownfield and greenfield projects, with a deterministic CI gate that blocks contradictions between the map, specs, and code while warning on non-blocking drift.
Blueprint Index — Living Architecture Map
A Spec Kit extension that keeps a living architecture map of your project honest — and gives you a deterministic, low-friction, machine-first CI gate that catches when the map, the specs, and the code drift apart, no matter how a change was made.
It doesn't change how you build. It keeps the map true, and it's designed so a CI step (or a CI agent) can detect and heal drift automatically.
What this is really about — drift, not retrieval. Getting an agent to read your codebase is increasingly handled by your editor/agent. The unsolved half is keeping a project's architectural picture current as code changes out-of-band: "code evolves, the specification does not… a linter does not flag it, CI does not flag it, the system ships with drift baked in." This extension is a deterministic gate for exactly that.
Who this is for
Use it if you practise spec-driven development (Spec Kit) on a real, evolving — often brownfield — codebase, you feel the specs and the architecture picture going stale as the code changes, and you want CI to catch that drift instead of discovering it later.
You probably don't need it if you're just starting SDD on a small or greenfield project (Spec Kit's core flow is enough), you want SDD lighter, or your pain is the agent not knowing your codebase — that's retrieval, handled by your editor/agent; this keeps the map current, it doesn't read the code for you.
How to integrate
- Install it into a Spec Kit project (below).
initonce — from existing code (--from-code) or a design doc — to create the map.- Add
checkto CI — this is the integration point; it fails the build only when the map factually contradicts the specs/code (see the gate below). - Keep building normally. The map maintains itself as the gate nudges you
(
distilla shipped slice,remapafter a refactor,init --from-codea new module).
The tiered coherence gate (the core)
check is a deterministic gate (no LLM) that classifies every issue into two tiers, so
it can run in CI without crying wolf on every commit:
- 🔴 HARD — the map contradicts reality → blocks the merge (exit 1). Precise,
low-false-positive:
- drift — a built spec the map doesn't index (e.g. a spec born from an external
tracker). →
distill - dangling — a section pointing at code that's been deleted. →
remap
- drift — a built spec the map doesn't index (e.g. a spec born from an external
tracker). →
- 🟡 SOFT — the map may be behind → advisory, does NOT block (exit 0). Coarse
signals where the map is usually still true at architecture altitude:
- stale — code changed under a mapped area (a refactor/hotfix, spec or not). →
remap - unmapped — new code that no section maps (a module added out-of-band). →
init --from-code <path> - unmanaged — a section
inithasn't processed yet. →init - unstamped — a mapped area with no baseline yet. →
restamp
- stale — code changed under a mapped area (a refactor/hotfix, spec or not). →
--strict promotes SOFT to blocking for teams that want full enforcement. The exit code
is a first-class signal, independent of output format.
Running it looks like this (human-readable on a terminal):
$ blueprint-state.sh check --human
HARD — the map contradicts reality (blocks merge):
DRIFT 007-refunds built spec not in the map → /speckit.blueprint-index.distill 007-refunds
SOFT — the map may be behind (advisory):
STALE src/payments code changed since mapped (b55500a1 -> 448a74e2) → /speckit.blueprint-index.remap src/payments
UNSTAMPED src/billing no git baseline recorded yet → blueprint-state.sh restamp --path src/billing
UNMAPPED src/notifications tracked code no section maps → /speckit.blueprint-index.init --from-code src/notifications
1 blocking, 3 advisory
$ echo $?
1
# .github/workflows/blueprint.yml — blocks only when the map is factually behind
- run: bash .specify/extensions/blueprint-index/scripts/bash/blueprint-state.sh check
Machine-first output — built to be consumed
The two machine surfaces — check (the gate) and next (the harness) — follow
the git/--porcelain convention: JSON when piped/non-interactive (CI, an agent),
human-readable on a terminal; --json/--human force either. (status is the
human dashboard and always prints prose — use check for a machine-readable view.)
{ "blueprint_schema": "1", "command": "check", "blueprint": "docs/blueprint.md",
"in_sync": false, "blocking": 1, "advisory": 1, "strict": false,
"issues": [
{ "severity": "hard", "type": "drift", "target": "007-refunds",
"detail": "built spec not in the map",
"remedy": { "run": "/speckit.blueprint-index.distill 007-refunds", "kind": "authored" } },
{ "severity": "soft", "type": "unstamped", "target": "src/billing",
"detail": "no git baseline recorded yet",
"remedy": { "run": "blueprint-state.sh restamp --path src/billing", "kind": "deterministic" } }
] }
Each issue carries a self-describing remedy and its kind, so a CI LLM backend can
self-heal:
check --json → for each issue, run remedy.run:
· kind=deterministic → apply + commit (safe, no LLM judgment)
· kind=authored → run the agent, land it as a reviewable PR
→ re-run check → exit 0 when the map matches reality
Be clear-eyed about the split: unstamped is the only deterministic remedy —
refreshing a baseline needs no judgment. Everything else (drift, dangling, stale,
unmapped, unmanaged) is authored, meaning an agent rewrites map prose and a human
reviews the PR. The kind field exists so CI never has to guess which is which.
Commands
| Command | What it does |
|---|---|
speckit.blueprint-index.init | Scaffold the map — from a design doc (greenfield) or --from-code to reverse-map existing code (brownfield). Idempotent. |
speckit.blueprint-index.status | Read-only dashboard: detailed / settled / context / unmanaged sections, drift, where each spec stands. |
speckit.blueprint-index.distill | Collapse a finished spec's section to a digest + pointer; stamp the slice's code baseline. |
speckit.blueprint-index.remap | Re-derive a section from current code + refresh its git baseline (resync after out-of-band changes). |
Plus the script-level gate the commands and CI share: blueprint-state.sh check (the
tiered gate) and blueprint-state.sh restamp (deterministic baseline refresh).
Install
specify extension add blueprint \
--from https://github.com/ogil109/spec-kit-blueprint/releases/latest/download/blueprint.zip
# or, for local development:
specify extension add /path/to/spec-kit-blueprint --dev
Requirements: a Spec Kit project (.specify/), Spec Kit ≥ 0.10, git (for the
code-baseline checks), and bash (Unix/macOS). A PowerShell port is verified at output
parity with the Bash oracle on pwsh 7.4 (Linux); Windows path handling is still unverified.
Quickstart
# Brownfield — reverse-map an existing repo into a code-owned map
/speckit.blueprint-index.init --from-code
/speckit.blueprint-index.status
# Greenfield — seed the map from a design doc
/speckit.blueprint-index.init docs/master-spec.md
# Build with your normal spec-kit flow; when a slice ships, collapse it into the map:
/speckit.blueprint-index.distill 001-some-slice
# Keep it honest in CI (blocks only on hard drift; --strict to block on advisories too)
blueprint-state.sh check
/speckit.blueprint-index.remap src/payments # after a change flagged STALE
The blueprint document
An annotated table of contents is the index + architecture map. Each managed section carries a provenance marker under its heading — the extension's deterministic record of what it has processed:
## 3. Payments
<!-- blueprint:section state=distilled owner=specs/007-refunds -->
> **Distilled — owned by `specs/007-refunds`** (implemented at `src/payments/`).
<!-- blueprint:code path=src/payments sha=a1b2c3 -->
Section states: detailed (holding pen), distilled owner=specs/<slug>, code
(brownfield), or context (framing — not a buildable slice). Code-mapping sections also
carry a git-baseline marker. The prose banners are cosmetic — the markers are what
the gate reads, so a hand-written banner can't fool it. init is idempotent and
non-destructive: it stamps unmanaged sections, preserves managed ones, and never
deletes content — so it also formalizes an existing master doc in place.
Autonomous harness (optional second payoff)
Because the map is externalized state and the oracle computes the single next action
deterministically, the same pieces are a harness for long, multi-spec agent sessions
— an agent loops on blueprint-state.sh next, re-grounding on the filesystem each step
so it can't drift. It's a documented pattern (no extra command); see
docs/autonomous-harness.md. tests/harness_loop_test.sh
proves the loop sequences specs correctly (parking, stop bounds); the agent's authoring
within a phase stays reviewed, not proven.
Honest boundaries
- Detection, not conformance. The gate flags that the map is behind reality (a spec not indexed, code that moved) — it does not verify the code correctly implements its spec, and it doesn't check architectural boundaries. That deeper conformance is a heavier, language-specific problem this deliberately doesn't tackle.
- A structural gate with one known blind spot. It detects new code (the
unmappedsignal) and changed mapped code, but it does not verify whether a distilled digest still faithfully reflects its spec — it checks the pointer, not the prose. Treat digests as human-reviewed content, not verified fact. - The friction dial is the bet. Making
staleadvisory (not blocking) is what makes the gate usable in real CI; the tradeoff is that out-of-band code changes are surfaced and reconciled, not hard-blocked (unless--strict). Whether this balance is right for a given team is exactly what real usage will tell us. - Map content is agent-authored.
init(mapping a repo) anddistill(writing a digest) are done by the agent and reviewed; only the gate and the oracle are deterministic. When the map feeds every spec, its authoring quality matters. - Two known edges. A
[NEEDS CLARIFICATION]marker that a formatter has wrapped across lines is not detected (the scan is line-based), so a spec with an open question could advance a step; and the unmapped-code scan word-splits its root list, so a top-level directory whose name contains a space is not scanned. Both are narrow, and the second is unreachable in most repos. - Prior art: the "spec↔code drift gate" concept has been articulated in the 2026 literature (e.g. arXiv 2606.27045). This extension's angle is being brownfield-first, language-agnostic (git baselines, not per-language static analysis), low-friction, and shipped as a spec-kit extension — rather than a greenfield, graph-based framework.
Status of this extension
- Bash oracle + tiered gate: tested —
tests/oracle_test.sh(state frontier, provenance, context) andtests/check_remap_test.sh(hard/soft tiers, the friction fix,--strict, and the JSON contract), against a real git repo. Dogfooded on a real 2,100-line brownfield project. - Harness loop: tested —
tests/harness_loop_test.sh. - PowerShell port (
scripts/powershell/blueprint-state.ps1): executed and diffed against the Bash oracle on pwsh 7.4 (Linux) — identical JSON, identical exit codes (default and--strict), identical recorded baselines, across every issue state. Windows itself is still unverified (path separators, git-for-Windows), so that's the open gap.
This is an early, honestly-scoped extension: the deterministic gate is tested and dogfooded; whether its low-friction balance is right for your team is exactly what we'd like to learn.
Support
Questions, bugs, or "it flagged X and shouldn't have" — please open an issue on the repository. Feedback on the gate's friction (false positives/negatives on a real repo) is especially welcome.
Contributing
Contributions welcome — this is a community Spec Kit extension. The oracle/gate is a single Bash script with no dependencies beyond bash + git, so the tests run anywhere:
bash tests/oracle_test.sh # state frontier, provenance, context
bash tests/check_remap_test.sh # the tiered gate: hard/soft, --strict, JSON contract
bash tests/harness_loop_test.sh # the autonomous-harness loop
Iterate locally with specify extension add /path/to/spec-kit-blueprint --dev. Please open an
issue to discuss anything larger than a fix before sending a PR. The PowerShell port is
parity-verified on Linux/pwsh; a Windows maintainer to confirm it there is very welcome.
Commits follow Conventional Commits and CI
validates them; versioning and the changelog are generated by
commitizen (uv sync --group dev, then
uv run cz commit / cz bump) — never hand-written. See
CONTRIBUTING.md.
Authors & acknowledgment
Built by ogil109, with AI assistance (Claude Code) per Spec Kit's contributing guidelines. The drift-gate concept builds on ideas in the 2026 spec-driven-development literature (see Honest boundaries).
License
MIT.
Stats
Version
Install
Using the Specify CLI
specify extension add blueprint-index --from https://github.com/ogil109/spec-kit-blueprint/releases/download/v0.2.0/blueprint.zip