speckeep: a spec-driven development workflow for coding agents
TL;DR — speckeep is a small spec-driven workflow for coding agents: specs, plans, tasks and proof live in plain markdown, agents get them as /spk-<phase> commands, and a CLI gate makes "done" checkable in CI. Single Go binary, MIT. Try it with speckeep demo ./my-demo.
Every team using a coding agent hits the same three failures, usually in the same week:
- Amnesia. You explain the same feature three sessions in a row, because context lives in a chat window that closed.
- Drift. The agent builds something reasonable — just not what you asked for. Nobody notices until review.
- Phantom "done". The agent says it's finished. No tests, no evidence, no trace from requirement to code.
Prompting harder doesn't fix this. The problem isn't the model — it's that there is no durable artifact between "what we want" and "what the agent did", and nothing that forces the agent to prove the second matches the first.
That's the gap speckeep fills. The workflow is a strict chain:
constitution -> spec -> [inspect] -> plan -> tasks -> implement -> archive
- constitution — the project's non-negotiables (stack, conventions, quality bar).
-
spec — one feature, with stable IDs: requirements
RQ-*and acceptance criteriaAC-*. - inspect (optional) — a deep quality review before you commit to a plan.
- plan — surfaces (files) to touch, decisions, risks.
-
tasks — ordered, phased, each with a
Touches:surface map. - implement — executes tasks, one phase at a time.
- archive — closes the feature once every task has proof.
Optional verify is an on-demand audit; propose is a one-shot fast lane for small changes; converge is the cheap closing loop.
Here's what that looks like in practice — init a workspace, read the health check, dry-run a refresh:
The idea: discipline per token
Most process fails on agents for one reason — it asks for too much context at once. speckeep's design rule is the opposite: every phase loads only the minimum it needs, and every phase leaves behind one compact artifact.
Each phase is a command you invoke in your agent. In Claude Code, Codex, Cursor, Copilot and others, that looks like:
/spk-constitution
/spk-spec Add CSV export to the reports table
/spk-plan csv-export
/spk-tasks csv-export
/spk-implement csv-export
The part that makes it different: proof, not vibes
Here's the mechanism that changed agent behaviour more than any prompt.
Every task in tasks.md must carry a Proof: line before it can be checked off, and every task maps to the surfaces it touches:
## Surface Map
| Surface | Tasks |
| ------------------------------------- | ----- |
| apps/api/src/routes/reports.ts | T2.2 |
| packages/reporting/src/csv.ts | T2.1 |
| apps/web/src/reports/ExportButton.tsx | T2.3 |
## Phase 2: MVP Slice
- [x] T2.1 Implement CSV serialization — the exporter produces headers + rows. Touches: packages/reporting/src/csv.ts
Proof: test packages/reporting/src/csv.test.ts TestSerializeReports
- [x] T2.2 Wire the export endpoint — the route streams the CSV. Touches: apps/api/src/routes/reports.ts
Proof: test apps/api/src/routes/reports.test.ts TestExportRoute
- [ ] T2.3 Add the button + empty state — the UI triggers export and handles zero rows. Touches: apps/web/src/reports/ExportButton.tsx
The CLI reads exactly those lines. If a task is marked done without proof, check says so by name:
$ speckeep check export-report .
verdict: blocked
detail: error [] closed task(s) without Proof in specs/active/export-report/tasks.md:
T1.1, T1.2 — add a Proof: line to tasks.md
speckeep guard is the same idea for CI — it exits non-zero while any active feature isn't closeable:
$ speckeep guard .
╔═════════════════════════════════════════════════════╗
║ speckeep guard ║
║ verdict: fail — 1 feature(s) are not ready to close ║
╚═════════════════════════════════════════════════════╝
- export-report implement implement blocked
So the agent's claims are checked by a machine, not by your patience — and because the gates are deterministic, the agent can run them itself and self-correct before it ever reports back.
Built for the repo you actually have: a large monorepo
This is where speckeep earns its keep for us. Our main repo is a monorepo with a lot of code across many packages. For an agent, that's a trap: read too little and it edits the wrong package; read too much and the context window is full of irrelevant files before the real work starts.
Three pieces fix that:
1. REPOSITORY_MAP.md — a navigation index the agent can trust.
Run /spk-repo-map (directly, or when a task changes structure) and speckeep generates/updates a compact map: entry points, top-level modules, key paths, and a "where to edit" table — all derived from the actual tree, kept under a line budget so it stays cheap to read. Instead of walking the repo, the agent opens the map, picks the right 2–3 surfaces, and starts.
2. CONSTITUTION.md — one source of truth for conventions.
In a monorepo, conventions differ per package and nobody remembers all of them. The constitution captures them once (language rules, layering, test expectations, what not to do), so every phase and every agent reads the same rules instead of guessing — and specs get checked against them.
3. spec.md + Touches: — an explicit, tiny surface area per task.
The spec pins the acceptance criteria; the task list pins the exact files each task may touch. The agent's working set is now "this feature, these surfaces" — not "this repo".
Put together, that's how a complex, cross-package task gets closed without the agent reading the whole monorepo: the map narrows where to look, the constitution narrows how to build, the spec and Touches: narrow what to change. And because the same artifacts persist, the next session doesn't start from zero.
A real cycle, end to end
Say you want CSV export on a reports page.
1. Init and spec
speckeep init . --lang en --shell sh --agents claude
/spk-spec --name "CSV export for reports"
The agent writes specs/active/csv-export-for-reports/spec.md:
## Goal
Allow users to download the reports table as a CSV file.
## Acceptance Criteria
**AC-001** Export produces a file
Given the Reports page has at least one row
When the user clicks "Export CSV"
Then a .csv file downloads with column headers and all visible rows
**AC-002** Empty state is handled
Given the reports table is empty
When the user clicks "Export CSV"
Then a friendly message is shown and no file is downloaded
2. Plan → tasks
/spk-plan csv-export-for-reports
/spk-tasks csv-export-for-reports
You now have a small, readable package — and it lives in your repo, not in a chat:
specs/active/csv-export-for-reports/
spec.md # goal + AC-001..AC-00N
plan.md # surfaces, decisions, risks
tasks.md # phases, Touches:, Proof:
verify.md # optional audit report
3. Implement, then close
/spk-implement csv-export-for-reports
Each task gets code and a Proof: line. When the last one is checked, the agent closes the loop:
$ speckeep converge csv-export-for-reports .
OK: feature is converged: tasks complete with valid Proof coverage — safe to archive
$ speckeep archive csv-export-for-reports . --compact
If there's a gap, it appends follow-up tasks and loops — with a hard stop after two rounds instead of grinding forever. And if you want a formal audit before archiving, set workflow.verify: required and the archive gate demands a verify: pass report first.
--compact keeps just summary.md plus a git pointer instead of copying every artifact. The whole feature is a handful of markdown files you can read in two minutes. That's the point.
Day one: adopt it in 5 minutes
- Install (details in Install below):
curl -fsSL "https://raw.githubusercontent.com/bzdvdn/speckeep/main/scripts/install.sh" | bash
- Init your real repo and confirm it's healthy:
speckeep init . --agents claude,opencode
speckeep doctor .
Write the rules down once — run
/spk-constitutionand point it at your stack, layering and test expectations. In a monorepo this is the highest-leverage ten minutes you'll spend.Map the codebase — run
/spk-repo-mapto generateREPOSITORY_MAP.md, and re-run it whenever the structure changes.Take one real (small) task through the chain:
/spk-spec <task> -> /spk-plan -> /spk-tasks -> /spk-implement
Watch the first Proof: line appear — that's the moment it clicks.
-
Wire the CI gate — copy
contrib/ci/speckeep-guard.ymlinto.github/workflows/, or add the action directly:
- uses: bzdvdn/speckeep/.github/actions/speckeep@main
with:
root: .
Now "done" is enforced on every pull request.
If step 5 feels heavy for a first try, use /spk-propose instead — same proof requirement, one command.
What changed for us
| Before | After |
|---|---|
| Re-explaining the same feature every session | The spec and tasks are already in the repo |
| Review = "did the agent do what we asked?" | Review = "do we agree with the spec?" |
| Cross-package work stalled on "which package owns this?" |
REPOSITORY_MAP.md answers it |
| "It's done" → "actually, no" loops |
Proof: catches it before a human does |
Why not just use AGENTS.md, ready-made skills, or another spec tool?
Fair question — and it's the one I'd ask.
vs. hand-rolled AGENTS.md / your agent's built-in skills. You absolutely can encode a process there, and there's zero setup. What you don't get is enforcement: nothing turns "you should add tests" into a failing exit code, and nothing survives as a durable artifact when the session ends. speckeep is skills — it ships as skill files and commands for 19 agents — but it also adds the two things skills alone can't: persistent artifacts and deterministic gates.
vs. personal skill packs (e.g. mattpocock/skills). Great resources, and genuinely complementary. Those skills make your agent sharper inside a session — interviewing you about a plan, driving TDD, reviewing code. speckeep makes your definition of done survive the session and gives CI a way to enforce it. You can run both: use interactive skills for the conversation, speckeep for the spec → tasks → proof spine.
vs. other spec tools (OpenSpec, Spec Kit). Same family, different tradeoff:
| Dimension | speckeep | OpenSpec | Spec Kit |
|---|---|---|---|
| Workflow style | Strict phase chain, narrow context | Fluid, artifact-guided | Thorough multi-step SDD |
| Default context | Smallest | Moderate | Largest |
| Artifact overhead | Low | Medium | High |
| Brownfield / monorepo | High (repo-map + constitution) | High | Medium |
| Machine-checkable "done" |
speckeep guard (exit code in CI) |
— | — |
| Runtime | One Go binary | Node | Python |
The short version:
Other skills make your agent smarter in a session. speckeep makes your definition of done survive the session — and gives CI a way to enforce it.
Works with the agent you already use
speckeep ships adapters for 19 targets: Claude Code, Codex, Cursor, Copilot, OpenCode, Windsurf, Cline, Amazon Q, Gemini, aider, Devin, Goose, Jules, Refact, Roo Code, Kilo Code, Qwen Code, Trae, Codiumate.
It's skills-first and it does the per-tool research for you, because the tools genuinely differ. In Claude Code, top-level skills are directly slash-invocable. In OpenCode, skills are model-invoked and not in the / palette — so /spk-<phase> is reached through the /skills picker. speckeep handles that so you don't find out the hard way.
speckeep init my-project --agents claude,opencode,cursor
It also writes an AGENTS.md block so any agent — even ones without a skills system — knows the workflow and the gates.
The escape hatches (because process shouldn't be dogma)
Real teams need to move fast sometimes. speckeep has explicit, bounded ways to skip:
-
/spk-propose— one-shot: idea →spec.md+tasks.md, straight to implement. Falls back to/spk-specif the idea is ambiguous. -
Express lane — small changes close from
spec.md+tasks.md;plan.mdis optional. -
/spk-hotfix— emergency fix outside the chain (≤ 3 files, no re-planning). -
/spk-challenge— adversarial review of a spec/plan when you want a hostile second opinion. -
/spk-scope,/spk-glossary,/spk-handoff,/spk-recap,/spk-rollback— small, single-purpose tools.
The discipline is strict where it pays off and skippable where it doesn't.
Migrating in
speckeep import openspec . # openspec/changes/<slug>/ -> speckeep layout
speckeep import speckit . # specs/<slug>/ -> speckeep layout
It rebuilds requirement/acceptance IDs where it can and never overwrites existing features. Coming from DraftSpec (this project's predecessor), speckeep migrate handles the move.
Install and try it in 30 seconds
One Go binary, no runtime, MIT licensed.
# Linux / macOS
curl -fsSL "https://raw.githubusercontent.com/bzdvdn/speckeep/main/scripts/install.sh" | bash
# or: brew install bzdvdn/speckeep/speckeep
# or: npx speckeep ...
Try a fully populated example without touching your project:
speckeep demo ./my-demo
speckeep dashboard ./my-demo
speckeep check export-report ./my-demo
Docs (EN/RU): https://bzdvdn.github.io/speckeep/
Repo: https://github.com/bzdvdn/speckeep
What it is not
I'd rather you adopt it knowing the tradeoffs:
- It's not an orchestrator. No daemon, no agents-on-agents, no vector DB. It's files plus a CLI.
- It is strict by design. If you hate checklists and IDs, this will feel like overhead — until the first time an agent's "done" turns out to be fiction.
- It optimises for brownfield monorepos. The value is highest on real codebases with messy history and many packages, not greenfield demos.
- It's young. The workflow is stable; the ecosystem around it is still growing.
Why we built it
We used agents daily in a large monorepo and kept paying the same tax: re-explaining context, re-reviewing drift, and re-verifying work that was reported as finished. The trio that finally moved the needle was repo-map + constitution + spec — a map of the codebase, one set of rules, and a durable spec with proof.
speckeep is the smallest structure we found that actually changes agent behaviour — because it's the one the agent can't argue with. Either the Proof: line is there or the gate fails.
If that resonates: star the repo, run speckeep demo, and tell me two things — which agent you use, and where the workflow breaks on your codebase. That feedback is what shapes the next release.


Top comments (0)