DEV Community

Cover image for speckeep: a spec-driven development workflow for coding agents
Bogdan
Bogdan

Posted on

speckeep: a spec-driven development workflow for coding agents

speckeep: a spec-driven development workflow for coding agents

TL;DRspeckeep 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:

  1. Amnesia. You explain the same feature three sessions in a row, because context lives in a chat window that closed.
  2. Drift. The agent builds something reasonable — just not what you asked for. Nobody notices until review.
  3. 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
Enter fullscreen mode Exit fullscreen mode
  • constitution — the project's non-negotiables (stack, conventions, quality bar).
  • spec — one feature, with stable IDs: requirements RQ-* and acceptance criteria AC-*.
  • 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:

speckeep: init a workspace (skills + AGENTS.md), inspect it, run doctor and a dry-run 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

speckeep dashboard: features, phase, ready-for and task progress

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
Enter fullscreen mode Exit fullscreen mode
/spk-spec --name "CSV export for reports"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

2. Plan → tasks

/spk-plan csv-export-for-reports
/spk-tasks csv-export-for-reports
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

3. Implement, then close

/spk-implement csv-export-for-reports
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

  1. Install (details in Install below):
   curl -fsSL "https://raw.githubusercontent.com/bzdvdn/speckeep/main/scripts/install.sh" | bash
Enter fullscreen mode Exit fullscreen mode
  1. Init your real repo and confirm it's healthy:
   speckeep init . --agents claude,opencode
   speckeep doctor .
Enter fullscreen mode Exit fullscreen mode
  1. Write the rules down once — run /spk-constitution and point it at your stack, layering and test expectations. In a monorepo this is the highest-leverage ten minutes you'll spend.

  2. Map the codebase — run /spk-repo-map to generate REPOSITORY_MAP.md, and re-run it whenever the structure changes.

  3. Take one real (small) task through the chain:

   /spk-spec <task>  ->  /spk-plan  ->  /spk-tasks  ->  /spk-implement
Enter fullscreen mode Exit fullscreen mode

Watch the first Proof: line appear — that's the moment it clicks.

  1. Wire the CI gate — copy contrib/ci/speckeep-guard.yml into .github/workflows/, or add the action directly:
   - uses: bzdvdn/speckeep/.github/actions/speckeep@main
     with:
       root: .
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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-spec if the idea is ambiguous.
  • Express lane — small changes close from spec.md + tasks.md; plan.md is 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
Enter fullscreen mode Exit fullscreen mode

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 ...
Enter fullscreen mode Exit fullscreen mode

Try a fully populated example without touching your project:

speckeep demo ./my-demo
speckeep dashboard ./my-demo
speckeep check export-report ./my-demo
Enter fullscreen mode Exit fullscreen mode

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)