Why I Run My Coding Agent Inside a Devcontainer
---
title: "Why I Run My Coding Agent Inside a Devcontainer"
published: true
description: "I limit what Claude Code can touch to the inside of a container, so I can use auto mode without worrying, and I use named volumes to decide which environment reads and which one writes."
tags: devcontainer, docker, claudecode, ai
canonical_url: fukurou.kompiro.dev
cover_image: fukurou.kompiro.dev
---
I do almost all of my development inside a devcontainer.
Visual Studio Code opens a container, and I run Claude Code inside it.
When I had Claude Code make the demo GIF for my README, the whole recording happened inside the container too.
I started using devcontainers long before coding agents came along.
My reason for using them has changed since then.
Now it is that I can decide how far an agent reaches, one container and one volume at a time.
This post describes where I draw those lines.
How I got started with devcontainers will be a separate post.
Summary
1. Keeping an agent's reach inside a container lets me use auto mode without worrying. The agent is cut off from my browser sessions and API keys, and experimental tools never land on the host.
2. Named volumes let me separate the environment that reads from the one that writes. In the OpenSpec setup I'm trying on my own, the spec container reads the code under development, and the development containers read the specs.
3. I don't recommend devcontainers to everyone. They can be tuned in fine detail, so there is a lot to learn. Fixing the configuration, though, is something you can hand to an agent.
Keep secrets and experiments out of the agent's reach
I have three reasons for keeping the agent inside a container.
The first is to make it easy to try development tools.
Tools around coding agents come and go quickly, and I often want to try something experimental.
I'd rather not install those tools on my Mac.
If they live in a container and don't work out, I can just rebuild the container.
The second is to keep secrets out of reach.
My browser on the host has plenty of logged-in sessions, and the host also holds various API keys.
This is also why I chose Playwright inside the container over computer use when making the demo GIF.
The third is accidental file deletion.
I hear about it less these days, but I did hear several stories of agents deleting files.
If only the files inside the container are in play, the damage stays inside that container.
With all three in place, I can use auto mode without worrying.
Even when the agent asks me for confirmation less often, I still know what it can touch.
There is one hole I leave open on purpose.
Claude Code's configuration directory (~/.claude) is bind-mounted from the host.
That way the container can use the authentication I completed on the host, and I can look back across the sessions of every project later.
Use named volumes to decide who reads and who writes
Once environments live in separate containers, some things need to be shared between them.
I connect them with named volumes.
In repositories that use compose, devcontainer.json points at a compose file through dockerComposeFile, and that file refers to a network and volumes created outside the project.
By default, Docker Compose creates a project and a network for each compose file.
Bringing a whole project up or down is convenient, but you can't rebuild just one service.
So I manage networks and volumes separately from the projects.
The simplest thing to share is credentials.
In this blog's repository, the GitHub CLI and dev.to credentials live in named volumes.
"mounts": [
"source=gh-config,target=/home/node/.config/gh,type=volume",
"source=devto-config,target=/home/node/.config/devto,type=volume"
]
The volumes outlive the container, so rebuilding it doesn't mean logging in again.
At the same time, the credentials stay off my Mac and out of the repository.
The source code itself lives in a named volume too.
Bind mounts on a Mac are slow.
With the code in a volume, another container can see the same code just by mounting that volume.
Example: a spec container that only reads the code
On my own, I'm trying out OpenSpec.
OpenSpec is a tool for writing the spec before the code, and it accumulates change proposals (called changes) in a spec repository.
Writing a change requires reading the existing source code.
I also wanted the agent to read the code as it currently stands in development.
So I mount the volume that holds the development container's source code into the spec container as well.
The agent in the spec container doesn't get to rewrite that source code.
In the spec container's Claude Code settings (settings.json), the source code volume is not listed in additionalDirectories.
The agent that writes specs only reads the code.
There is also a mount in the other direction.
The development containers mount the spec volume.
That lets the development side check how the specs are progressing.
The backend and the frontend are developed independently in their own containers, and both see the same specs.
| Container | Mounts | What the agent writes |
| --- | --- | --- |
| Spec | The spec volume and the volume with the code under development | Specs only |
| Backend development | The backend source code and the spec volume | Backend code |
| Frontend development | The frontend source code and the spec volume | Frontend code |
Containers decide what an agent can touch, and volumes decide which environment reads and which one writes.
With the read and write directions set per container, I can run several agents side by side without them trampling each other's workspaces.
Keep the production image minimal and bring your own tools
There is also a line around what goes into the container.
The image I ship to production should contain only the files the service needs to run.
A development environment, on the other hand, needs room for whatever tools help me develop.
So I build on the production Dockerfile and add development tools with devcontainer features and dotfiles.
I manage dotfiles with yadm and tool versions with mise.
One reason I bring my dotfiles into the container is worktrees.
Developing with agents means using a lot of worktrees.
For reopening and switching between them, I want the tools my hands already know, such as fzf.
The work may happen inside a container, but the environment I operate by hand should feel the same as always.
Devcontainers are not for everyone
Devcontainers have their annoyances.
Changing devcontainer.json means rebuilding the container.
Every small tweak means waiting for a rebuild, so I'm careful when I edit it.
Disk usage doesn't bother me.
They also limit your choice of editor.
Newer IDEs built for AI agents, such as Orca, are awkward to combine with devcontainers.
That said, the Claude Code extension for Visual Studio Code is improving quickly too.
Would I recommend devcontainers to everyone? No.
They can be tuned in fine detail, which makes them hard to use casually, and beginners have a lot to learn.
Still, if you ask Claude Code or Codex to fix your devcontainer configuration, they do a good job.
If you want your development environment as code that you can reproduce, I do recommend them.
Takeaways
I keep using devcontainers because they let me decide, with containers and volumes, how much I hand to an agent.
Inside a container, the agent can work in auto mode while my secrets and experimental tools stay separated from the host.
Connected by named volumes, environments can share the same code and specs while keeping the reader and the writer apart.
The OpenSpec setup is still an experiment.
For a while, I'll watch how splitting the spec and development containers changes the way I write and work through changes.
OpenSpec 1.16 (30.10.) warnt bei Szenarien ohne GIVEN/WHEN oder THEN; mit --strict schlägt die Prüfung fehl. Für KI-Coding sinnvoll: Schon die Spezifikation braucht eine Ausgangslage und ein erwartetes Ergebnis.
github.com/Fission-AI/OpenSpec/releases/tag/v1.16…
11 views
BMAD Method (Part 1): Spec-Driven Development Where the Human Stays in Control
---
title: BMAD Method (Part 1): Spec-Driven Development Where the Human Stays in Control
series: BMAD Method
description: Why I care about spec-driven development whatever the framework, and how BMAD handles both a single change and a product from scratch around a human-approved intent.
tags: ai, bmad, specdrivendevelopment
---
As a software architect and senior software engineer, I keep watching the same change happen in the way we build software. In the first series I wrote about GitHub Spec Kit, and I stayed on one idea that I still think matters most: spec-driven development (SDD). Write the intent first, make it explicit, let the agent build against it, then check the result against what was written.
That idea does not depend on a framework. Spec Kit is one way to apply it, BMAD Method is another, and a markdown file in your repo is a third. In this series I look at BMAD Method, and in this first article I stay on the concepts and the commands. I do not show a finished result yet.
My angle is the same as before: not how fast an agent writes code, but who decides what gets built and who answers for what is produced. I think this is the question the industry is starting to ask. Anthropic has been talking about an AI Native Playbook, and BMAD has been moving in that direction for a while. This is a personal view, not a verdict.
What Is Spec-Driven Development?
Let's start from the problem. Many developers have had the same experience with an AI coding tool. The agent writes code quickly, the code often runs, and yet nobody on the team can say why it was written that way. Two sessions later the intent is gone, buried in a chat history, and the next change starts from a guess.
I call this vibe coding. I do not think the problem is the model. The problem is where the context lives. If the intent exists only in a prompt, it disappears when the session ends. If it exists in a document that the agent reads and the human reviews, the team can inspect it, change it, and keep it.
SDD, for me, comes down to four points:
- The intent is written down before the code. In a file, not in a chat.
- The agent works inside that intent. It does not reinterpret it silently.
- The human approves the intent and judges the result. The agent does not own the definition of done.
- The spec is versioned with the code. When the intent changes, the change is visible.
As in the first article, I would say the rigor of the spec can vary (spec-first, spec-anchored, spec-as-source), and these four points hold at every level.
Mental Model: the framework is a way to apply the idea at scale, not the idea itself.
!Image description
<!-- IMAGE 01 (done, images/01 png, source svg alongside): Diagram with four boxes in a row: "Intent (written)", "Spec (reviewed by human)", "Code (built by agent)", "Result (judged by human)". Under the first and last box, a label "human responsibility". Under the middle one, "agent works inside the spec". Clean, minimal, two colors. -->
BMAD in a Nutshell
BMAD stands for Breakthrough Method of Agile AI-Driven Development. It maps familiar roles (analyst, product manager, UX designer, architect, developer) onto AI agents, and it keeps the work in documents that the agents read and the humans review.
Two ideas matter most for me. The first is that each document has one owner and one writing skill. The Product Requirements Document (PRD) is the source of the product definition, and nothing else claims to define it. The planning docs say that documents are "contracts between people first and input to the skills second". The second idea is a rule: nothing downstream reinterprets the PRD. If a story needs an answer the PRD does not have, the answer goes into the PRD first, and the derived documents are regenerated.
The other thing BMAD gives you is more than one path. The first decision is about size, not tools. The build documentation says a change of roughly 500 lines, across a few files, fits one build session. The planning guide asks the question from the other side: is the intent already well defined? If it is, you hand it to a build, or to the epics and stories skill when the work is bigger. If it is not, you use the analysis skills first, in any order, until it is. The planning skills write the requirements down; they do not decide what you want.
Trivial, you review it yourself: edit directly, no process
One session (about 500 lines): intent -> /bmad-build -> result
Epic-sized: intent -> brief, PRD, UX, architecture, epics and stories -> one /bmad-build per story -> retrospective
Project-sized: several epics, shared decisions first, then the epic path for each
!Image description
<!-- IMAGE 02 (done, images/02 png, source svg alongside): Decision tree. Start node: "Is the intent well defined?". "No" branch to "Analysis skills (brainstorming, forge idea, brief, PRFAQ)" looping back. "Yes" branch to "How big is the change?" with four exits: Trivial -> "Edit directly"; One session -> "/bmad-build"; Epic-sized -> "Plan, then /bmad-build per story"; Project-sized -> "Several epics, shared decisions first". -->
BMAD also names its skills by phase. The planning guide groups them as Analysis, Planning and Solutioning, and Build is the phase that follows (the older dev.to articles call it Implementation). Analysis is optional, and its skills run in any order. Planning is where the PRD and the UX documents are written. Solutioning is where the architecture is decided, and where the epics and stories and the sprint status are produced. Build takes one story at a time. I use these four names in the rest of the article. One note: the skill catalog of the version I have installed (6.12.4) labels its skills only plan and ship, so the four names are the guide's grouping, not a label you will see in the tool.
!Image description
<!-- IMAGE 03 (done, doc/article/images/03-bmad-phases.png): four colored columns, Analysis -> Planning -> Solutioning -> Build, each with its skills and the files it produces. Groups from docs.bmad-method.org/plan/choose-a-planning-path/; skills of the installed BMAD 6.12.4 (epics, sprint planning, code review, retrospective). -->
Mental Model: size the process to the work, and make sure the intent is clear before anything is built.
Setting Up
The version I have installed is BMAD 6.12.4, the stable one. It installs from the project directory with one command:
npx bmad-method install
The installer sets up the modules and the skills for the coding tool I choose (Claude Code in my case). It writes the skills into .claude/skills/ and a _bmad/ folder with the configuration. In Claude Code the skills are typed in the slash form (/bmad-build, /bmad-prd), and that is the form I use in this article. When I am unsure where to start, there is /bmad-help.
The online docs now describe a newer v7 preview, installed with the Skills CLI, with some different names (for example a product owner skill called bmad-agent-po). I follow the version I use, and I say where the docs differ.
A Simple Example: a Todo List
I use the same todo list as in the Spec Kit series, so the two approaches can be compared on the same problem. There are two situations, and they lead to two different paths. In both I show the commands and not the results.
Path One: Adding a Flag to a Todo List I Already Have
Suppose the todo list is already implemented, with add, edit and delete. I want to add a "done" flag to each item and toggle it from the list view. The change is small, clear and low risk, and it fits in one session. This is the short path, and for this path I need only one skill: bmad-build. It takes an intent, investigates, plans, implements, reviews, and fixes what it finds.
Below is the flow from the build documentation, redrawn in my own style with the same structure (source: docs.bmad-method.org/build/build-a-change/). I walk through it node by node, because each node is a decision that somebody has to own.
!Image description
<!-- IMAGE 04 (done, doc/article/images/04-build-flow.png, editable source 04-build-flow.svg): the build flow of docs.bmad-method.org/build/build-a-change/ redrawn with the same nodes, loops and labels in a different style. Keep the source in the caption. -->
How to read the diagram. The main line runs from top to bottom: Initial intent, Clarify and route, Plan, Approved plan, Implement, the "Fits AC?" check, Review, Present, Result. Dashed lines show where a human takes part: the interview during clarification, the optional plan review, and the review of the result. A one-shot mode skips the planning nodes and goes from Clarify and route straight to Implement. The loops are the interesting part: a patch goes back to Review, a bad plan goes back to Plan, an intent gap goes back to Clarify and route, a rejected change goes to the bin (Void), and anything unrelated is deferred to a file.
Step 0: Size the Work (is it one session?):
For this change the answer is yes: a few files and far fewer than 500 lines. The docs give the rule. If it fits, use bmad-build. If it is too big, plan first. If you are unsure, ask bmad. A trivial change that you will review yourself does not need the process at all, and I would not use it for a one-line typo.
Step 1: Start a Fresh Chat (no shared context):
I open a new chat in the AI IDE. The docs warn that reusing a session from another workflow can mix contexts, and in my experience that is where wrong assumptions come from. A fresh chat means the agent starts from the files, not from what we said about the previous feature.
Step 2: Give the Intent (rough is fine):
/bmad-build Add a "done" flag to each todo item, toggle it from the list view, and keep the state after reload.
This is the Initial intent node. The docs say the intent can be rough, and it can come before, with, or after the command. It can also be an issue link, or a story from the epics list (/bmad-build story 2.3 builds story 3 of epic 2, and I use that form in Path Two). I prefer to write the intent in full for a change like this one. A rough intent is allowed, but it moves the cost to the questions the agent asks later.
Step 3: Clarify and Route (resolve the intent from evidence):
This is the Clarify and route node. The agent reads the codebase and any planning documents. Clear requests go ahead without a turn of questions. Anything the repository cannot settle becomes an open question on a finished design, not an interview before work starts. The human part is to answer those questions carefully, because wrong answers here are the costliest to fix later. In the todo case, I would expect a question about whether "done" items stay in the list or move to a separate view. That is my decision, not the agent's.
Step 4: Plan and Approve (the optional gate):
The agent evaluates the settled design on three facts: intent gaps, irreversible actions, and the footprint of the change. If all three are clean, it takes the light path: a minimal plan and the implementation in the same session, reviewed afterwards. If anything is flagged, it writes a full plan, and each intent gap becomes a question I must answer before approval. I approve the plan if it describes the right thing, and I push back if not, because fixing the plan is cheaper than fixing the code. For the todo flag, I would expect the light path. If the agent flags a migration of the stored data, the plan is where I decide it.
Step 5: Implement, Check, Review (the agent's own gates):
The Implement node is the agent's work. The "Fits AC?" check compares the change with the acceptance criteria that the build plan recorded. Then the Review node starts, and the agent reviews its own work with independent reviewers. The diagram names three lenses:
- Blind Hunter: finds problems without the bias of the implementation context.
- Edge Cases Hunter: looks for forgotten corner cases.
- Verification Gap Finder: asks whether the tests really cover the change.
The review ends in a triage, and the diagram shows where each outcome goes. A patch fixes issues that belong to this change and returns to Review. If the code is wrong because the plan was weak, the flow returns to Plan. If the plan is wrong because the goal was wrong, it returns to Clarify and route. A rejected change goes to Void. Unrelated pre-existing issues are deferred to deferred-work.md (the diagram spells the name with an underscore, the file in the project uses a hyphen). Then the agent commits locally, and runs the test suite if the project has one.
I like that the loops are explicit. A review that can only say fixed or not fixed hides the cause of the problem, and here the cause has to be named.
Step 6: Present and Review the Result (the human gate):
The Present node is the agent's short summary, with next steps: create a pull request, walk through the change, or make another change. The Result node is mine. I run the walkthrough or skim the diff, I tell the agent what to fix (it can iterate in the same session), and when I am satisfied I ask it to push the commit and open the PR.
Two things can still go wrong after this step, and I think it is worth being clear about both.
If the change turns out to be wrong after I accepted it. The agent works on my local copy and commits there. If I pushed that commit and then find a problem, the way back is the ordinary one in git: undo the commit with a new commit, so the history stays intact and nobody has to rewrite what is already shared:
git revert HEAD
HEAD is the last commit, so this creates a new commit that cancels exactly what the agent added (in our example, the "done" flag). I do not try to patch the problem inside the old chat. I start a fresh chat and run /bmad-build again, with the intent rewritten to say what I missed the first time (for instance: "the flag must survive a page reload"). This is the same idea as the rest of the article: the intent is the thing I correct, and the code follows it. This is a git practice that fits the flow, not a step that BMAD runs for me.
What the agent chose not to fix. During review the agent can find a real problem that does not belong to the current change. It does not fix it silently and it does not drop it: it writes it into deferred-work.md (the DEFER outcome in the diagram). Each entry names the story it came from, a one-line summary and the evidence. I read this file after every run. It is a backlog written by the agent, and a backlog nobody reads is where problems go to be forgotten. Reading it is part of my responsibility as the human who controls the result: for each entry I decide whether it is a new change to run later, a note to keep, or something to drop on purpose.
Path Two: Writing a Todo List From Scratch
Now suppose there is no todo list yet. I want a todo app with due dates and filters, kept in the browser. This is no longer one change. It is a body of work with several build units, so one /bmad-build is not enough. The planning documents become the contract, and each step reads files that the previous step wrote.
Every step runs in a fresh chat (/clear first). I show the real commands, and I name the files each step reads and writes. I do not show what is inside them: that is for the next article.
!Image description
<!-- IMAGE 05 (done, images/05 png, source svg alongside): Horizontal chain of ten boxes: "Brainstorm (optional)" -> "Brief" -> "PRD" -> "UX (optional)" -> "Architecture" -> "Epics and stories" -> "Readiness check" -> "Sprint status" -> "Build, story by story" -> "Retrospective". Under each box the file it writes: brainstorm-intent.md, brief.md, prd.md, DESIGN.md + EXPERIENCE.md, ARCHITECTURE-SPINE.md, epics.md, PASS/CONCERNS/FAIL, sprint-status.yaml, spec-N-M-*.md, retrospective. A dotted arrow from "Retrospective" back to "Build" labeled "next epic". -->
Step 1: Brainstorm (optional, what and why, no technology):
/bmad-brainstorming A simple todo list web app. Explore features, UX ideas and what must stay out of version 1.
A coach runs the session in the stance I choose: facilitator (no ideas from the coach), creative partner (ideas traded) or ideate for me. It reads nothing, because the idea is in the command. It writes a run folder under _bmad-output/brainstorming/ with brainstorm-intent.md (my decisions, kept apart from the ideas the coach offered) and a .memlog.md. If the idea is still half-formed there are two more analysis skills, /bmad-forge-idea to pressure-test it and /bmad-deep-recon to research a competitor or a technology. A personal view, not a verdict: if I cannot write the intent in three sentences after this step, I am not ready for a PRD.
Step 2: Product Brief (what and why, in one page):
/bmad-product-brief Create a product brief for a simple todo list web app. Use the brainstorming result at _bmad-output/brainstorming/brainstorm-todo_list-<date>/brainstorm-intent.md as the main input and treat its "Decisions" table as settled.
The skill asks whether I want to create, update or validate, and whether I take the Fast path or the Coaching path. It reads brainstorm-intent.md and writes brief.md, addendum.md (the depth that does not belong in the brief) and a .memlog.md, in _bmad-output/planning-artifacts/briefs/. Then, in a fresh chat, I validate it before moving on:
/bmad-product-brief validate the brief at <brief path>
Step 3: PRD (what to build, not how):
/bmad-prd Create the PRD for the todo list using the brief at <brief path> and the brainstorming intent at <intent path>. Features in order: (F0) foundations and storage; (F1) the list: add, tick, delete; (F2) due dates, overdue sign and filters.
The PRD is the source of the product definition, and every later document derives from it. The skill has three intents, create, update and validate, and a Fast path or a Coaching path. Functional requirements get stable ids (FR-1, FR-2, ...), and what the skill inferred is tagged [ASSUMPTION] so that I can correct it. It reads the brief, the addendum and the intent, and writes prd.md and a .memlog.md in _bmad-output/planning-artifacts/prds/. Validate and update are two more commands:
/bmad-prd validate the PRD at <prd path>
/bmad-prd update the PRD at <prd path>: <what to change>
Edits belong in the PRD, not in the stories, so the documents derived from it can be generated again. This is the whole point of the design.
Step 4: UX (optional, how it looks and how it behaves):
/bmad-ux Create the UX documents for the todo list from the PRD at <prd path>. Simple, calm, keyboard friendly, one screen.
The skill captures my vision and does not impose its own. It reads the PRD and writes two peer documents, DESIGN.md (how it looks) and EXPERIENCE.md (how it behaves), in _bmad-output/planning-artifacts/ux-designs/, with mockups when I ask to see options. It is optional: I would skip it only if I accept designing those details later, during the builds. A fresh chat validates it:
/bmad-ux validate the UX documents at <ux folder>
Step 5: Architecture (how, only where two builders could disagree):
/bmad-architecture Create the architecture for the todo list from the PRD at <prd path>, DESIGN.md and EXPERIENCE.md at <ux folder>. Decide: front-end framework, where tasks are stored, the task data model, the testing strategy.
The output is not a full technical document. It is a short architecture spine that records only the decisions that two units, built independently, could make in incompatible ways. The skill gives a decision a stable id (AD-1, AD-2, ...) only if the call is non-obvious and a real trade-off. In coaching mode it shows me the alternatives and I choose. In coaching mode it also writes SOLUTION-DESIGN.md, a plain-language companion for people who read the project without building it (the spine wins if the two differ). It writes ARCHITECTURE-SPINE.md, that companion and a .memlog.md in _bmad-output/planning-artifacts/architecture/. This is where my review matters most, because a wrong shared decision spreads to every story:
/bmad-architecture validate the architecture at <architecture path>
Step 6: Epics and Stories (work cut by user value):
/bmad-create-epics-and-stories Create the epics and stories list from the PRD, UX documents and architecture. Create exactly three epics, in this order: Epic 1 Foundations; Epic 2 Task list; Epic 3 Due dates and filters. Every story needs acceptance criteria.
It reads the PRD, the UX documents and the spine, and writes one file, _bmad-output/planning-artifacts/epics.md. Every functional requirement is mapped to an epic, and every story has acceptance criteria in the Given, When, Then form and fits one build session. I check the epic and story numbers, because every build command from now on uses them.
Step 7: Readiness Check (the gate before the build):
/bmad-sprint-planning check implementation readiness
The skill reads the planning documents the way a skeptic reads a handoff, and answers PASS, CONCERNS or FAIL. On CONCERNS or FAIL I fix the planning documents (/bmad-prd update, /bmad-ux, /bmad-architecture, or /bmad-create-epics-and-stories again) and run the check again. If something major changes later, there is a command for that too:
/bmad-correct-course <description of the change>
Step 8: Sprint Status (one file that says where every story is):
/bmad-sprint-planning run sprint planning
It reads epics.md and writes _bmad-output/implementation-artifacts/sprint-status.yaml, with every epic, story and retrospective as a key. All stories start as backlog, then move to ready-for-dev, in-progress, review and done.
Step 9: Build One Story at a Time (the implementation phase):
/bmad-build story 1.1
/bmad-build does not pick the next story by itself: I give it the number each time, one story per fresh chat, in order. Each run follows the flow of Path One, with the diagram as the guide. It reads the story in epics.md, the architecture spine and, for UI work, DESIGN.md and EXPERIENCE.md. It writes the code, a local commit, a spec file for the story (spec-1-1-<slug>.md), an epic-1-context.md on the first story of the epic, and it appends what does not belong to the story to deferred-work.md. It also syncs sprint-status.yaml: the story moves to review. The agent does not close its own work: I review, and I decide when a story is done. An optional extra check, in a fresh context, is /bmad-code-review. I would not use the unattended build skill for the first stories: they set the patterns for the rest.
Step 10: Retrospective (close the epic):
/bmad-retrospective 1
When the stories of the epic are finished, the skill reads the evidence the epic left (the specs, the diff, the commits, the sprint status) and judges the epic against the criteria it set for itself. Every finding carries a source, and a claim with no source is dropped. The result is a retrospective with findings, action items and an acceptance decision. A failing epic never closes as quietly accepted.
Looking at these ten steps together, the pattern is always the same. Each skill writes one document or one piece of code. Each document has one writer. Each gate has a human decision. The agent works inside the boundaries that the earlier documents set.
What BMAD Writes to Disk
So far I have shown commands. What makes the process work is the files, because each step reads what the previous one wrote. BMAD keeps two folders at the project root, and they have different jobs.
- _bmad/ is the metadata. The installed version and modules, one row per skill, the user and project names, the output folders, the team overrides, and the script that writes the logs. It holds no deliverable.
- _bmad-output/ is the handoffs. Every document a skill produces, in one run folder per document, plus the sprint status and the build specs.
This is the layout BMAD leaves on disk for the todo list.
<prj_root>/_bmad/
_config/manifest.yaml installed version, modules, coding tools
_config/skill-manifest.csv one row per installed skill
core/config.yaml user name, project name, languages, output folders
bmm/config.yaml
custom/config.toml team overrides, committed to the repo
custom/bmad-build.toml facts every build session treats as context
scripts/memlog.py the script that appends to the .memlog.md files
<prj_root>/_bmad-output/
brainstorming/brainstorm-todo_list-<date>/
brainstorm-intent.md
.memlog.md
planning-artifacts/
briefs/brief-todo_list-<date>/ brief.md, addendum.md, .memlog.md
prds/prd-todo_list-<date>/ prd.md, .memlog.md
ux-designs/ux-todo_list-<date>/ DESIGN.md, EXPERIENCE.md, .memlog.md
architecture/architecture-todo_list-<date>/
ARCHITECTURE-SPINE.md, SOLUTION-DESIGN.md (coaching mode), .memlog.md
reviews/VALIDATION-REPORT.md
epics.md
implementation-artifacts/
sprint-status.yaml
epic-1-context.md
spec-1-1-create-the-project-with-the-quality-gate.md
deferred-work.md
Here is the handoff chain in one table: what each step reads, and what it writes for the next one.
| Step | Reads | Writes |
|---|---|---|
| Brainstorm | nothing (the idea is in the command) | brainstorm-intent.md |
| Brief | brainstorm-intent.md | brief.md, addendum.md |
| PRD | brief, addendum, intent | prd.md |
| UX | prd.md | DESIGN.md, EXPERIENCE.md |
| Architecture | PRD, DESIGN.md, EXPERIENCE.md | ARCHITECTURE-SPINE.md, plus SOLUTION-DESIGN.md in coaching mode |
| Epics and stories | PRD, UX documents, spine | epics.md |
| Readiness check | epics.md and the documents behind it | PASS, CONCERNS or FAIL |
| Sprint status | epics.md | sprint-status.yaml |
| Build, per story | the story, the spine, UX documents for UI work | code, spec-N-M-*.md, epic-N-context.md, deferred-work.md, status moved to review |
| Retrospective | the specs of the epic, git history, sprint-status.yaml | the retrospective and its decision |
Each run folder also holds a .memlog.md. It is the memory of that document, an append-only log with one line per decision, assumption or change, written through the memlog.py script and never edited by hand. This is the shape of one (the lines are illustrative, for the todo PRD):
---
topic: Todo List PRD
updated: 2026-11-01T12:10
---
- (decision) Working mode: Fast path, entry point Vision + Features
- (assumption) Selected filter survives a reload
- (event) PRD finalized
Three things follow from this design:
- A fresh chat can continue. A step reads files, not the history of the previous chat, so I can close the session and resume tomorrow.
- Every decision has a trace. The memlog says what was decided and why, and which assumptions are still open.
- A change starts at the source. If a story needs an answer the PRD does not have, the answer goes into the PRD first, and the later steps run again.
BMAD does not keep one log for all the sessions: each document has its own memlog. If I want the view across the steps (which session ran which skill, and what it read and wrote), I would keep a small file for it.
!Image description
<!-- IMAGE 07 (done, images/07 png, source svg alongside): Two columns. Left, "_bmad/": a small stack labeled "config, manifest, overrides, memlog.py". Right, "_bmad-output/": a row of document icons (brainstorm-intent.md, brief.md, prd.md, DESIGN.md + EXPERIENCE.md, ARCHITECTURE-SPINE.md, epics.md, sprint-status.yaml, spec-N-M.md) connected by arrows, each arrow labeled "read by the next step". Under each document a small ".memlog.md" tag. -->
What the Method Gives You
- Context that survives sessions. Decisions live in files, so a new chat starts from documents, not from memory.
- Version control for decisions. The PRD, the architecture and the stories live in git, next to the code.
- Predictability. I know the likely end state of a session, because it was written before the session started.
- Several sizes of process. A one-session change and a whole product use the same vocabulary with very different amounts of ceremony.
The other side, with the same sincerity as before:
What the Method Does Not Give You
- Correctness by default. An agent can implement the wrong thing precisely. A good spec reduces guessing, it does not remove it.
- Zero overhead. For a typo or a CSS tweak, even the short path is too much.
- Freedom from handoff problems. Agents with different roles can still make conflicting assumptions. The documents make the conflict visible, but a human has to resolve it.
- Room in the context window. Specs, architecture and stories consume context, so they must stay concise.
- A replacement for judgment. The framework tells you when to stop and ask. It does not tell you what the product should be.
The Role of the Human
In every path, the agent produces a lot, and the human is responsible for what is accepted. On the short path I answer the open questions, approve the plan when it is flagged, and review the result. On the long path there are moments where a human decision blocks the next step. These are the ones I meet in the version I use (the planning guide of the online docs lists five sign-off points for the newer version):
| Moment | What I judge | What it blocks |
|---|---|---|
| Brainstorm intent | Which directions survive, the Decisions table | The brief and the PRD |
| PRD validation | The findings report | UX and architecture |
| Architecture validation | The decisions that are mine, the corrections | Epics and stories |
| Readiness check | PASS, CONCERNS or FAIL | Sprint planning and the first build |
| Plan approval and story review | The plan when flagged, the diff, deferred-work.md | Marking the story done |
| Retrospective decision | Did the epic meet its criteria | The next epic |
Each of these leaves a written trace, in a memlog, a report or a status file. In a regulated company that is the audit trail, and in a small team it is the best record of why a decision was made. I think this is the clearest statement of responsibility I have seen in an agent workflow.
Mental Model: bounded autonomy, not full automation.
!Image description
<!-- IMAGE 06 (done, images/06 png, source svg alongside): Timeline of the from-scratch path with six human icons above: "brainstorm intent", "PRD validation", "architecture validation", "readiness check", "story review", "retrospective decision". Below it a band labeled "agent produces, human accepts or rejects". -->
Takeaways
1. A spec is a contract between people first, and input for agents second. If the intent is not clear to the people involved, no agent will make it clear for them. Writing it down is where the work starts.
2. Size comes first. One session, one epic and one project need different amounts of process. BMAD gives me a single command for the small change and a planning path for the large one, and choosing between them is my call.
3. The loops in the build flow are the point. A bad plan, an intent gap and a deferred problem each go back to the layer that caused them. That is what keeps a wrong decision from being buried in the code.
4. The human approves the plan and judges the result, and the agent works inside both. The responsibility for what is produced does not move. What changes is where I spend my attention: on the intent, the gates and the diff.
5. The handoff between steps is a file, not a chat. That is what lets a fresh session continue, and what leaves a written trace of every decision. A change starts in the source document, so the later ones can be regenerated.
What Comes Next
BMAD is one answer to a question that many people are asking at the same time: how do we give an agent enough written intent to work well, and keep a human in charge of what comes out? I do not think it is the only answer, and I would not want this series to be only about one tool.
In the next article I want to make the example more concrete. I also want to keep the radar on, because spec-driven development is moving fast: what the major players are doing about it, how the SDLC changes when an agent does part of the work, and which other approaches are worth exploring. Two that I already have on my list are OpenSpec by Fission-AI, and the agent-skills collection by Addy Osmani. I have not formed a view on them yet, and I would rather look before I write about them.
There will be at least one more article after this one. Stay tuned.
What is your experience with planning documents and agents? Do you keep the spec in the repo, in a tracker, or in the chat? I would love to read your experience in the comments.
SDD desde cero: cómo dejé de tirar código de Claude Code a la basura
Hace unos meses tiré a la basura dos días de trabajo de Claude Code.
No estaba mal hecho. Estaba muy bien hecho. El problema es que no era lo que hacía falta: le había pedido algo en una frase, se puso a programar y, cuando lo vi, ya era tarde.
Desde entonces trabajo con SDD (Spec-Driven Development, desarrollo guiado por especificaciones). Este artículo es lo que me habría gustado leer al empezar: qué es, por qué cambia tanto con agentes de código y cómo probarlo en una tarde.
El problema: el agente es rápido, pero no lee la mente
Un agente de código hace en minutos lo que antes llevaba días. Pero trabaja con lo que entiende de un mensaje. Si el encargo era ambiguo, construye otra cosa, y te das cuenta al revisar el código, cuando ya hay mil líneas.
Y hay un segundo problema que se ve menos: quien pidió el cambio (alguien de negocio, de soporte, un cliente) no tiene forma de saber cómo va. Pregunta en el chat, alguien mira el código, contesta «casi está».
La idea: primero se acuerda, después se programa
SDD es una regla sencilla: antes de tocar código, se escribe qué se va a construir y una persona lo aprueba.
Con agentes, ese papel lo escribe el propio agente. Tú solo lo lees y dices sí o no. El malentendido sale antes de programar, cuando arreglarlo cuesta una frase, y no después.
Las palabras que vas a oír
- Requisito. Lo que tiene que poder hacer alguien cuando esté hecho, en palabras normales. «Quien gestiona descarga las facturas del mes en un fichero.»
- Propuesta. El plan del agente: qué va a cambiar, por qué y qué queda fuera.
- Criterio de aceptación. Cómo sabréis que está bien. «El fichero se abre en Excel con sus tildes.» Cada requisito tiene al menos uno.
- Especificación. Cómo debe comportarse el sistema, escrito para que quede. El siguiente cambio parte de ahí.
- Tareas. Los pasos del agente para hacerlo.
- Aprobación. El sí de una persona. Sin él, el agente no programa.
Un ejemplo de principio a fin
1. Marta pide algo: «Exportar las facturas del mes en CSV». Escribe tres requisitos: que quien gestiona pueda descargarlas, que se abran bien en Excel y que solo salgan las de su empresa.
2. El agente escribe la propuesta. Lee la tarea y escribe qué va a cambiar, qué queda fuera y cómo se comprobará cada requisito.
3. Alguien la aprueba o pide cambios. Hasta entonces, el agente no programa.
4. El agente programa y prueba, y al terminar comprueba cada criterio de aceptación contra lo acordado.
5. Marta lo ve llegar: cada requisito pasa de «sin empezar» a «en desarrollo», «probado» y «en producción».
¿No es más lento?
Añade una parada: aprobar. En mi caso son cinco minutos leyendo mientras tomo mate. A cambio, se programa una vez lo acordado y no varias veces lo malentendido.
No todo necesita SDD: un bug o una incidencia se arreglan y ya. SDD es para lo que cambia el comportamiento.
Cómo probarlo esta tarde (sin herramientas de pago)
La pieza base es OpenSpec, un formato abierto para que el agente escriba propuestas y especificaciones dentro de tu repositorio, en ficheros de texto.
npm install -g @fission-ai/openspec@latest
cd tu-proyecto
openspec init
A partir de ahí, en Claude Code le pides que proponga el cambio antes de implementarlo. Te deja en openspec/changes/ la propuesta, las especificaciones y las tareas. Lo lees, corriges lo que no cuadre y le dices que adelante.
Con esto ya tienes el 80 %: el agente piensa antes de programar y tú decides con el plan delante.
Lo que me faltaba (y por qué acabé construyendo algo)
OpenSpec resolvía mi parte. Pero la propuesta vivía en el repositorio, y quien pedía el cambio no la veía nunca. La aprobación era «lo leí y dije OK en el chat», y nadie fuera del terminal sabía en qué punto estaba cada requisito.
Por eso hice Atalaya, un gestor de trabajo (tareas, sprints, Kanban) con SDD dentro: los requisitos se escriben en la tarea, el agente informa su propuesta por MCP, una persona aprueba en la tarea (el agente no puede aprobarse solo) y cada requisito enseña su estado hasta producción. Las especificaciones siguen siendo ficheros de OpenSpec en tu repo: si un día lo dejas, se quedan contigo.
Está en acceso anticipado y es gratis. Pero lo importante del artículo no es la herramienta, es la regla: que el agente proponga y una persona decida antes de que se programe. Empieza con OpenSpec a pelo y verás la diferencia.
---
¿Cómo lo hacéis vosotros? ¿Revisáis lo que va a hacer el agente antes, o el código después? Me interesa mucho saber qué os funciona.
AIと2週間で、問題7,000問の金融教育ゲームを作った開発プロセス【OpenSpec × Claude Code】
はじめに
新社会人向けのお金の学習ゲーム「マネラン」を、AIのコーディングエージェントと一緒に作っています。
給与明細・税金・社会保険・NISA・詐欺対策などを、1回3〜5分のクイズで学べる、Duolingo のようなアプリです。
最初のコミットから約2週間で、次のところまで来ました。
項目
数
コミット
106
完了した仕様変更(OpenSpec の change)
54
仕様(capability)
33
コース / ユニット / レッスン
17 / 72 / 713
問題
7,130問(8種類の出題形式)
用語集
417語
テスト
Flutter 54ファイル、pgTAP 11ファイル、Edge Function・Web のテスト
構成は Flutter(iOS / Android / Web)+ Supabase(Auth・Postgres・Edge Functions)+ Next.js(LP と管理画面)です。
この記事では「AIに何を任せて、人は何をしたか」「どうすれば2週間でここまで進むのか」を、実際のリポジトリの中身を見せながら紹介します。
AIで開発してみたい人、AIに書かせたらコードが散らかって困っている人の参考になればうれしいです。
1. まず仕様書を書いて、AIに「地図」を渡す
開発を始める前日に、製品仕様書(docs/product-spec.md)を書きました。
誰のためか(MVPは入社1〜2年目の新社会人)
何を解決するか(「手取りがなぜ減るのか分からない」「詐欺の標的になりやすい」など)
何をしないか(金融商品の勧誘・個別の投資助言はしない、コインを現金に換えない)
ゲームの仕組み(育つ貯金箱、間違えた問題が敵になる「ミスモンスター」、詐欺メッセージを見抜く「詐欺バスター」など)
ポイントは「やらないこと」まで書くことです。
AIは頼まれていない機能も気を利かせて作りがちですが、スコープ外がはっきりしていると、提案がぶれにくくなります。
2. OpenSpec で「仕様 → 設計 → タスク → 実装」を1変更ずつ回す
このプロジェクトの中心にあるのが OpenSpec です。
変更のたびに、次の4つの文書を AI と一緒に作ってから実装に入ります。
openspec/changes/<変更名>/
├── proposal.md # なぜ・何を変えるか・影響範囲
├── specs/ # 要件と受け入れシナリオ(WHEN / THEN)
├── design.md # 設計上の決定と、その理由
└── tasks.md # 実装タスクのチェックリスト
実装が終わったら archive して、変更の内容を正本の仕様(openspec/specs/)に取り込みます。
2週間で archive した変更は54件。1日あたり4件ほどのペースです。
2026-10-15-migrate-to-supabase
2026-10-16-add-challenge-mode
2026-10-17-add-marketing-site
2026-10-21-enhance-lesson-game-effects
2026-10-22-add-profile-image-upload
2026-10-25-add-mascot-answer-feedback
2026-10-27-add-slack-event-notifications
...
なぜ「いきなり実装」させないのか
AIに「〇〇を作って」と直接頼むと、それらしいコードはすぐに出てきます。ただ、規模が大きくなるにつれて次のことが起きます。
前に決めたこと(データの持ち方、命名、画面の余白)と違う実装が混ざる
「なぜこうなっているのか」が誰にも分からなくなる
レビューする人が、差分のコードだけを見て判断しなければならない
先に proposal と design を書かせると、人がレビューするのは数百行のコードではなく、数十行の日本語になります。
方向がずれていれば、コードを書く前に直せます。
タスクには「どう確かめるか」まで書く
tasks.md の各タスクには、完了の条件を具体的に書きます。たとえば Slack 通知を追加したときのタスクはこうです。
- [x] 2.3 supabase/tests/90_auth_notify_test.sql(pgTAP)で、判定関数が 2.1 の各経路を
正しく分類すること(確認前のメールは null、確認と同時のログインは登録だけ、
トークン更新は null、ゲストは null)と、Vault が無いときにトリガーが何もせず
auth.users の更新が成功することを確かめて supabase/tests/run.sh が通る
「実装する」ではなく「〇〇のテストが通る」「ブラウザで△△を確かめる」で終わらせると、AIが自分で完了を判定でき、人の確認も楽になります。
3. AIへの「憲法」を1か所に書く
OpenSpec の config.yaml には、すべての変更で守るべき前提を書いておけます。マネランではこう書いています(抜粋)。
context: |
成果物(proposal/specs/design/tasks)は日本語で書く
アプリはFlutter(iOS/Android/Web)。ゲームのルールは純粋な Dart のドメイン層(app/lib/domain)に置く
利用者データの書き込みは RLS と Postgres 関数(RPC)で守る。複数の表にまたがる反映は1つの RPC(1トランザクション)で行う
コイン・利息・ストリーク・XPの不正対策は、サーバー側の検証で行う。日付判定にはサーバー時刻(now())を使い、端末時刻を使わない
有料化(課金・プレミアムプラン・広告)は当面行わない
実在の金融商品・企業名・サービス名を学習コンテンツや詐欺ケースに使わない。投資助言・勧誘にあたる表現を入れない
ここに書くのは「コードを読んでも分からない決定」だけです。
ファイル構成のようにコードを読めば分かることは書きません。逆に「端末時刻を信じない」「広告は入れない」のような方針は、書いておかないと AI は毎回それらしい別案を出してきます。
4. 大きな方針転換も、早いうちなら AI と一緒に一気にやれる
開発2日目に、バックエンドを Firebase から Supabase に移すと決めました。
理由は、週ごとのリーグ(昇格・降格)などのサーバー処理を安全に作るには、Firestore のルールだけでは足りなかったからです。本番のデータがまだ無く、移行のコストが最も低いタイミングでした。
この変更も、proposal で「なぜ今か」「何が BREAKING か」「どこに影響するか」を書いてから実装しています。
学習結果の反映を1つの Postgres 関数(apply_activity)にまとめ、学習日はサーバー時刻で決める
増分の上限・二重反映をサーバー側で検証する
RLS で「本人と運営だけが読み書きできる」ことを pgTAP でテストする
ゲームのルール(貯金箱の利息・ストリーク・XPの計算)は Flutter にも Supabase にも依存しない純粋な Dart の層に分けておいたので、ドメイン層は一行も変えずにバックエンドだけを入れ替えられました。
AI に任せる量が多いほど、こうした「変わりにくい部分」と「入れ替わる部分」の境目が効いてきます。
5. コンテンツ7,000問も AI と作る。ただし「質の基準」が先
問題は全17コースで7,130問あります。これを手で書くのは現実的ではないので、AI に下書きを作ってもらっています。
ただ、何も決めずに作らせると、次のような「AIっぽい問題」が大量にできます。
正解だけが長くて丁寧なので、読まなくても当てられる
誤答が「何も起きない」「請求額が半分になる」のように明らかにおかしい
正解がいつも「専門家に相談する」
そこで content/QUALITY.md に問題の質の基準を書きました。
誤答の選択肢
誤答は、実際によくある誤解・ありがちな計算ミス・似た制度との取り違えから作る。
- よい例(数字): 正しい計算で使わなかった値・時価と簿価の取り違え・年と月の取り違え・旧制度の数字
- 正解だけが長い・丁寧・「確かめる」「相談する」で終わる、という形で正解が分かってしまわないようにする
- 「専門家に相談する」を正解にするのは、本当に個別の判断が要る場面だけ
さらに、形式のルール(1レッスン10問、問題タイプ3種類以上、難易度の配分、用語集にない用語を使わない など)は、content/tools/validate_content.py で機械的に検証します。
「質」は文章で基準を渡し、「形式」はスクリプトで検証する。この2段構えで、量と質を両立させています。
一斉にやらせない
コンテンツを大きく書き直すとき、最初は複数のコースを並列で一斉に AI に任せていました。結果は、コースごとに基準の解釈がばらつき、見直しが追いつかなくなりました。
今は「1コース書き直す → 検証 → 人が読む → 次のコース」と順番に進めています。
AI は並列にいくらでも動かせますが、ボトルネックは人のレビューです。レビューできる速さに合わせるほうが、結局早く終わります。
なお、お金の制度は改定されるため、問題はすべて下書き扱いにし、FP などの専門家の監修を経て公開する流れにしています。AI が書いた専門的な内容を、そのまま「正しいもの」として出さないためです。
6. デザインの統一も「仕様」にする
UI の改善も OpenSpec の変更として扱っています。
unify-page-margins(全画面の余白をそろえる)
vibrant-gold-theme → unify-dark-game-theme(色をトークンで一元管理する)
redesign-badges-ui、redesign-piggy-screen、reorganize-status-screens など
AI に画面を1枚ずつ作らせると、画面ごとに余白や色が微妙に違うものができあがります。
「余白はこの値」「色はこのトークンから選ぶ」を spec にしておくと、新しい画面を作るときも AI が既存のルールに合わせてくれます。
7. 「動くまで」ではなく「運用できるまで」をAIとやる
アプリ本体以外にも、運用に必要なものを同じ流れで作っています。
Next.js の LP と、content/ を差分で取り込む管理画面(Google ログイン + TOTP)
GitHub Actions での Flutter Web / LP / Supabase のデプロイ
Firebase Analytics / サイト分析と、管理画面の KPI ページ
登録やログイン、LP のボタンのクリックを Slack に通知する Edge Function
SEO(構造化データ・サイトマップ・Search Console)
個人開発では後回しにしがちな部分ですが、AI がいると「ついでにやっておく」ハードルがかなり下がります。
まとめ:AI開発で効いたこと
仕様書に「やらないこと」まで書く。AI の提案がぶれにくくなる
いきなり実装させず、proposal / design / tasks を先に書かせる。人は日本語をレビューすればよくなる
タスクの完了条件を「〇〇が通る」で書く。AI が自分で完了を判定できる
コードから読み取れない決定だけを、1か所(config)にまとめて書く
変わりにくいドメインと、入れ替わるインフラを分ける。大きな方針転換にも耐えられる
質は文章の基準で、形式はスクリプトで守る
人のレビューの速さに合わせて、1つずつ進める
AI が速く書けるようになった分、人の仕事は「何を作るか決めること」と「確かめること」に寄っていきました。
コードを書く時間が減った代わりに、仕様と基準を書く時間が増えた、というのが2週間やってみての実感です。
さいごに:マネランを遊んでみてください 🐷
マネランは、1回3〜5分で、社会人に必要なお金の知識が身につく無料の学習ゲームです。
「額面と手取りの違い」「住民税が2年目から増える理由」「NISA と iDeCo の使い分け」などを、クイズで少しずつ
続けるほど育つ貯金箱で、複利のしくみを体験
間違えた問題は「ミスモンスター」になって再登場。倒して図鑑を埋めよう
本物そっくりの偽メッセージを見抜く「詐欺バスター」で、詐欺への備えも
登録なしのゲストでもすぐに始められます。
この記事を読んで「AIで作るとこうなるのか」と思った方も、「給与明細、実はよく分かっていない…」という方も、ぜひ一度遊んでみてください。
👉 アプリ: maneran.web.app
👉 紹介ページ: maneran-lp.web.app
遊んでみた感想や、「こんな問題がほしい」「ここが分かりにくい」といった声も大歓迎です。コメントでお気軽にどうぞ!
The OpenSpec update I want first is the one that writes nothing
I added a local note to a generated OpenSpec command, asked what an update would do, and checked the files afterward. The preview reported a replacement. Every file hash stayed the same.
Then I ran the update. The local note disappeared.
That is a useful distinction to see before your coding assistant starts following a different set of instructions. OpenSpec 1.15.0 adds update --dry-run, with a JSON form that lists planned file actions. It also ships a standalone CLI. The interesting part for an existing project is getting to inspect the replacement before accepting it. [1]
!Executed OpenSpec fixture: add a local note, preview an update with unchanged file hashes, then apply the update and observe that the note is removed.
Original diagram of the checked fixture below. It describes generated instruction files, not an AI coding session.
The version number wasn’t the question
An assistant integration has more moving parts than the executable. There are generated commands, skills, and the project’s own context. A current CLI does not tell you that every generated file matches its current template—or that you want it to.
My fixture starts with a clean Claude integration and deliberately customizes .claude/commands/opsx/explore.md. It then checks three separate things:
- Did the preview identify that command as an update?
- Did previewing leave both the project and isolated configuration trees untouched?
- Did applying the update actually replace the customization?
The last check matters. A plan is useful evidence about an intended action; the resulting files establish what happened. 🔎
Here’s the output from OpenSpec 1.15.0:
preview changed files: 0
custom command: update
local note retained after update: False
remaining planned changes: 0
The disappearing note is deliberate in this disposable example. In a real project, it could be the sentence you wanted your assistant to keep remembering. The update cannot decide whether that sentence was important to you.
Run the same disposable check
For a POSIX shell with Python 3.10 or newer, create a scratch directory and install the pinned standalone release into it. The installer selects a compatible release asset and checks its checksum. Other supported installation routes are in the project’s documentation. [2]
mkdir openspec-preview-lab
cd openspec-preview-lab
curl -fsSL https://raw.githubusercontent.com/Fission-AI/OpenSpec/v1.15.0/scripts/binary/install.sh -o install.sh
OPENSPEC_VERSION=v1.15.0 OPENSPEC_INSTALL_DIR="$PWD/.tools" sh install.sh
.tools/openspec --version
Save the following as preview_demo.py, then run python3 preview_demo.py from that directory. It uses a temporary project and separate configuration/data directories. The claude tool choice generates integration files; this script does not launch Claude or make a model request. 🧪
import hashlib
import json
import os
import subprocess
import tempfile
from pathlib import Path
binary = Path(os.environ.get("OPENSPEC_BIN", ".tools/openspec")).resolve()
def manifest(root):
return {str(p.relative_to(root)): hashlib.sha256(p.read_bytes()).hexdigest()
for p in root.rglob("*") if p.is_file()}
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
project = root / "project"
project.mkdir()
env = {**os.environ, "XDG_CONFIG_HOME": str(root / "config"),
"XDG_DATA_HOME": str(root / "data"), "DO_NOT_TRACK": "1",
"OPENSPEC_TELEMETRY": "0"}
def run(*args):
return subprocess.run([str(binary), *args, str(project)], env=env,
check=True, capture_output=True, text=True).stdout
run("init", "--tools", "claude", "--profile", "core", "--no-animation")
command = project / ".claude/commands/opsx/explore.md"
command.write_text(command.read_text() + "\nLOCAL_NOTE: review this customization.\n")
before = manifest(root)
plan = json.loads(run("update", "--dry-run", "--json"))
assert manifest(root) == before
edits = [c for c in plan["changes"] if c["path"] ==
".claude/commands/opsx/explore.md"]
assert len(edits) == 1 and edits[0]["action"] == "update"
print("preview changed files:", len([p for p in before
if manifest(root).get(p) != before[p]]))
print("custom command:", edits[0]["action"])
run("update")
assert "LOCAL_NOTE" not in command.read_text()
print("local note retained after update:", "LOCAL_NOTE" in command.read_text())
again = json.loads(run("update", "--dry-run", "--json"))
assert again["changes"] == []
print("remaining planned changes:", len(again["changes"]))
The manifest includes relative file paths and content hashes. Comparing the complete dictionaries catches additions and deletions as well as changed contents. Merely checking modification times would be a weaker test: a file can be rewritten with identical bytes.
The isolated configuration directory is intentional. The preview can include OpenSpec configuration actions alongside project instruction changes. I want the disposable check to include those effects without borrowing settings from another project. The source defines XDG_CONFIG_HOME as a supported override. [3]
Read the action, then inspect the difference
The JSON describes which files would be added, updated or deleted. That is not a semantic review of the new instructions. action: update cannot tell you whether a sentence became less precise, a local restriction disappeared, or a workflow now expects another artifact.
⚠️ My mistake would be treating a clean preview as permission to replace everything. “This command is generated” and “this command contains no useful local changes” are different facts.
For a maintained project, I’d first save the current files in version control. I’d inspect the preview, apply the intended update, then read the actual diff before using the assistant integration. If a customization belongs in a project-owned instruction file, move it there deliberately and check that the relevant tool reads it. Avoid assuming every tool has the same override rules.
✅ This fixture checks one generated Claude command and the isolated trees around it. It establishes the preview’s behavior for that case. It does not establish preservation rules for every integration, validate the meaning of generated instructions, or prove that an agent will obey them.
The useful addition is modest and practical: an update now has a readable “before” state. I’d rather discover the disappearing sentence there than after asking an assistant why it stopped doing something.
References
1. OpenSpec 1.15.0 release: standalone install and update dry run.
2. OpenSpec installation documentation.
3. OpenSpec 1.15.0 configuration-directory implementation.
Asset credit: original diagram of the executed disposable OpenSpec fixture.
AI disclosure
AI was used to draft the article.
5 reactions
OpenSpec's Oct 24 release adds an update dry-run: see which files would be added, changed or deleted without writing them. I appreciate software that shows the furniture plan before rearranging the room. github.com/Fission-AI/OpenSpec/releases/tag/v1.15…
8 views
OpenSpec - Spec-Driven Development for AI Coding Assistants
OpenSpec is a spec-driven development framework with over 73,000 GitHub stars and 5,000 forks. Perfect for both solo and team projects, it helps you and your AI stay honest on a single repo. Learn more at openspec.dev. Link in first comment 👇 #OpenSpec #AI #CodingAssistants
🔗 Fission-AI/OpenSpec
3 likes · 532 views
SDD наоборот: не программируем по спекам, а получаем их на сдачу
Недавно мне нужно было внести изменение в проект, где не было никакого SDD-фреймворка. Вообще никакого, Карл! Ни proposal, ни design, ни дельт спек, ни даже скромного tasks.md в уголке. Я морально приготовился к долгому онбордингу агента: сейчас он будет час ходить по коду, путаться в модулях и спрашивать, где тут вход. А модель просто разобралась в коде, нашла места будущего вмешательства, сделала изменение, и оно спокойно прошло человеческое ревью у кодовнера. Без единой спеки. «А что, так можно было?»
После этого я посмотрел на свой рабочий проект с OpenSpec, на папку openspec/ с её двумя сотнями файлов, и задал себе резонный вопрос: зачем мы генерируем, храним и заносим под git кучу артефактов, которые современной модели не нужны? Кому мы пишем эти бумаги, если главный читатель прекрасно обходится без них?
Из этого вопроса вырос SlimSpec, плагин для Claude Code. Он берёт из SDD то, что работает, и выкидывает остальное. На реальном проекте сопоставимое изменение обошлось ему в 29,7M токенов против 45,7M у OpenSpec, а в git не попало ни строчки процессных файлов. Дальше расскажу, откуда взялась идея, как устроен флоу, покажу цифры и то, чем пришлось заплатить. Спойлер: заплатить пришлось, бесплатных обедов не бывает даже в мире LLM.
Зачем вообще был нужен SDD
Ещё недавно модели были слабее, контекст маленьким, сабагентов не было. Работали так: в одной сессии составляешь подробный план, в следующей его реализуешь. Модель постоянно теряла контекст, как золотая рыбка, которая на третьем круге аквариума снова знакомится с замком. И память о проекте приходилось куда-то складывать, иначе каждая сессия начиналась с «привет, я новый джун, расскажите мне всё с начала».
Spec-driven development закрывал ровно эти боли: маленький контекст, отсутствие сабагентов, нужда в подробном плане. Записал всё на бумажку, бумажку положил в репозиторий, следующая сессия бумажку прочитала. Надёжно, как швейцарские часы. Так он и стал стандартом.
Тогда же появились два главных, на мой взгляд, фреймворка: OpenSpec и Superpowers. Я поработал с обоими, основным у меня стал OpenSpec. За что я их ценил:
режим explore (в Superpowers он называется brainstorming), где дизайн складывается раньше плана. Это вообще лучшее, что случилось с AI-разработкой: сначала думаем, потом пишем код, а не наоборот;
сам план и спецификации;
у OpenSpec ещё и мерж спек: в живой спеке остаётся только важное. Superpowers этого лишён напрочь и просто копит design-файлы, как бабушка пакеты под раковиной. Выкинуть жалко, а найти нужный уже нельзя.
В SDD-флоу, каким его видело сообщество, всё это ложилось идеально.
Где OpenSpec начал тормозить
В пет-проектах я долго сидел на OpenSpec с «китайскими» моделями и проблем не видел. Скорее наоборот: код стало легче писать и поддерживать, пропали семантические дубли (ну вы знаете, когда в проекте вдруг находятся три функции форматирования даты), агент чаще делал то, что нужно, и делал правильнее.
На коммерческом проекте мы командой тоже выбрали OpenSpec, и поначалу я был в этом уверен на сто процентов. Через пару месяцев стало понятно, что флоу очень медленный. Особенно когда мы ушли от ручного ревью. Подписка корпоративная, лимиты жалеть незачем, мы шпарили в несколько окон терминала над разными фичами, а процесс всё равно тянулся, как очередь в МФЦ за справкой о том, что у тебя есть справка.
Что тормозило:
После proposal идут ещё четыре артефакта: design, tasks, дельты спек и прочее. Мы их практически не читали. Но они честно писались, коммитились и уезжали в архив. Без бумажки ты букашка, а с бумажкой… ну, тоже букашка, только с бумажкой.
Любая правка в незаархивированном change выливается в ещё один change. Передумал по ходу? Будьте добры, заполните заявление по форме.
Перед архивацией обязателен ребейз. И ещё надо попросить агента «ручками» проверить мерж спек, потому что кто-то другой мог залезть и «испортить» секцию, в которую вписывается MODIFIED-блок.
Мой личный рекорд бюрократии выглядит так. Нужно было выпилить фичу: ненужный кусочек экрана. Задача на удаление, что может быть проще? Удалить код, удалить тесты, закрыть тикет. Итоговый дифф:
Почти 5,5 тысячи строк ушло, и почти столько же пришло. Пришли, конечно, спеки: proposal о том, зачем удаляем, design о том, как удаляем, tasks о том, в каком порядке удаляем, и дельты REMOVED о том, что именно удалили. Чтобы выкинуть 5 тысяч строк, пришлось написать 5 тысяч строк. Это как сдать старый диван на свалку, но сначала заполнить на него техпаспорт, акт приёма-передачи и опись царапин.
А потом случился тот самый проект без фреймворка. И пазл сложился.
Основная сессия и есть дизайн
Всю механику я давно отдаю сабагентам. Основная сессия у меня превратилась в разговор: брейнштормлю фичу с агентом, и тут же рождаются дизайн и план. Отступления от плана фиксируются там же, новых changes не нужно. Если доработка разрастается, агент сам предлагает вынести её за скоуп, в non-goals. Никаких заявлений, никаких форм. Сказал «давай иначе», и стало иначе.
Выходит, источник знаний о фиче у меня уже есть, это сама сессия. Файлы нужны только на случай, если сессия потеряется или её пережуёт компакшн. Как запасной парашют: хорошо, что он есть, но прыгать с ним каждый день необязательно. Отсюда и «SDD наоборот»: не спека ведёт работу, а работа в конце оставляет после себя спеку.
Артефакты изменения: OpenSpec против SlimSpec
Вокруг этой идеи я и решил собрать свой фреймворк. Взять лучшее у предшественников и сделать легче, быстрее и дешевле. Классическое «я его слепила из того, что было», только с TDD.
Как устроен SlimSpec
Внутри только скиллы и описания агентов для Claude Code. Скриптов, хуков и CLI нет, ломаться там особо нечему. Ставится и запускается так:
/plugin marketplace add yushman/slimspec
/plugin install slimspec@slimspec
/slimspec <идея>
sourcecraft.dev
Весь цикл на одной картинке:
Флоу SlimSpec: explore → plan → apply → verify → ground
Начинается всё с explore. Сабагент-сканер читает спеки модулей, потом код, и приносит короткую сводку: что тут есть, где что лежит, что может сломаться. Дальше основная сессия меня грилит: один вопрос на одно решение, независимые вопросы приходят пачкой. Ощущение как на собеседовании, только собеседуют твою же идею, и это полезно: половина «очевидных» решений на втором вопросе оказывается не такой уж очевидной. Итог ложится в explore.md: цель, non-goals, решения с отвергнутыми альтернативами, риски. Отдельных proposal и design нет, explore и есть спека изменения. К плану сессия сама не переходит, это решаю я.
В plan планировщик раскладывает работу в tasks.md по волнам. Волна делится на дорожки (lanes) из связанных задач. Дорожки одной волны трогают непересекающиеся файлы, поэтому идут параллельно. Слона едят по частям, но если частей несколько и тарелки разные, их можно есть одновременно. У каждой задачи сразу записан первый падающий тест.
Волны и дорожки в tasks.md
apply короче всех: на дорожку по implementer’у, он идёт по задачам по порядку и на каждую приносит red и green. После волны основная сессия гоняет весь набор тестов, чтобы две параллельные дорожки не подрались где-нибудь на стыке.
С verify интереснее. Ревьюер сверяет результат с планом и дизайном и смотрит, что red упал по делу, а не из-за опечатки или забытого импорта. Тест, который падает с ModuleNotFoundError, это не red, это просто красный. Код-ревью он отдаёт встроенному /code-review. Баги в коде автоматически уходят обратно в apply. Вопросы к дизайну приходят ко мне через refine: он правит explore.md и возвращает в apply только инвалидированные задачи. Галя, у нас отмена, но только трёх позиций, остальные пробиваем. Если два автоматических круга исправлений не помогли, сессия зовёт меня.
Про ground ниже отдельно, там самое главное.
Остановок две: после explore и после plan. На каждой сессия показывает подробный разбор. После explore это дизайн с диаграммами «было/стало» и ссылками на path:line, после plan все волны, дорожки и тест на каждую задачу. Остальное едет само и дёргает меня только вопросами. Можно спокойно пойти за кофе. Можно даже за вторым.
Сабагенты не разговаривают с пользователем
Решения принимает основная сессия. Сабагенты работают по принципу «каждый сверчок знай свой шесток»: сделал свою часть и отчитался. Отчёт короткий и структурированный, без логов и диффов:
status: DONE | BLOCKED | FAILED
task: T3
files: [src/auth/token.ts, src/auth/token.test.ts]
decisions: ["used existing clock abstraction"]
deviations: ["renamed validate → verifyToken"]
tdd:
red: "token.test.ts: rejects expired token — FAIL (expected 401, got 200)"
green: "12 passed"
questions: []
sourcecraft.dev
Упёрся в открытый вопрос: останавливается со статусом BLOCKED. Самостоятельно ничего не додумывает и «как-нибудь сам» не решает. Основная сессия спрашивает меня и перезапускает агента с ответом. Контекст основной сессии остаётся чистым, без простыней тестовых логов, но в нём лежит каждое решение и каждый итог.
Основная сессия и сабагенты
TDD и ревью вшиты во флоу
По-моему, TDD и код-ревью уже стали стандартом, так пусть лучше живут во фреймворке, чем в чьей-то дисциплине. Дисциплина, как известно, заканчивается в пятницу вечером. TDD проверяется не хуком, а по свидетельствам: задачу без red-прогона verify не примет. Ты не пройдёшь! (с) Гэндальф, ревьюер на полставки. Где TDD неприменим (конфиг, стили, миграции), задача помечается test: none — <причина> с альтернативной проверкой, и все такие исключения видны на гейте плана. Спрятать «ой, тут тесты не нужны» в середину списка не получится.
Два временных файла
Изменение живёт в .slimspec/changes/<slug>/, там лежат explore.md и tasks.md. Папку SlimSpec сам добавляет в .gitignore, а после ground удаляет. Отряд не заметил потери бойца, и правильно сделал: всё полезное из бойца к этому моменту уже переехало в спеки. Историю хранят коммиты и обновлённые спеки. Потерялась сессия? /slimspec <slug> продолжит с того места, где остановились.
Grounding: единственное, что осталось от SDD
Последний этап, ground, наверное, единственное, что роднит SlimSpec с классическим SDD.
Из изменения дистиллируются долговременные знания: поведение, инварианты, контракты, решения. План и процесс выбрасываются. Кому через полгода интересно, что задача T3 шла во второй волне? Правильно, никому. Дальше это вливается в спеку модуля, и здесь главное отличие от OpenSpec. Мерж идёт не по ADDED/MODIFIED/REMOVED-блокам. Его делает агент, которому понятны причины, структура и дизайн изменения. Противоречащее утверждение он переписывает, а не дописывает рядом. Иначе спека быстро превращается в «было так, но потом стало вот так, хотя смотри пункт 7». Потом агент проверяет, что обновлённая спека покрывает цель изменения и не спорит с принятыми решениями.
Grounding: дистилляция и слияние в CLAUDE.md модуля
Результат ложится во вложенный CLAUDE.md нужного модуля. Claude Code сам подгружает такие файлы, когда работает в этой директории, так что спека попадает в контекст без лишних движений и ровно там, где нужна. Одна спека на модуль вместо россыпи файлов по capability. Не надо помнить, какую спеку подсунуть агенту: он зашёл в модуль, и спека уже там.
Цифры
Хватит теории, давайте мерить. На SlimSpec я перевёл два своих проекта. Замеры делал на одном из них, looqlog. Это просмотрщик логов на Rust с веб-интерфейсом, раньше он жил на OpenSpec и переехал командой /slimspec:migrate-openspec.
Миграция
У нас было 23 файла спек, 23 изменения в архиве, 200 файлов в openspec/ и 733 килобайта истории. Не то чтобы всё это было нужно агенту, но раз уж начал собирать артефакты, становится трудно остановиться.
OpenSpec
SlimSpec
Спеки поведения
23 файла, 2 941 строка, ~155 КБ
3 файла, 484 строки, ~34 КБ
Архив изменений
23 изменения, 12 394 строки, ~733 КБ
0
Корневой CLAUDE.md
130 строк
121 строка
Файлов в openspec/
200
0
Миграция looqlog: OpenSpec против SlimSpec
Сценарии WHEN/THEN влились в требования, которые они и описывали. Пустые разделы Purpose и шаблонные SHALL ушли (SHALL, SHALL NOT, SHALL ALWAYS… спека звучала как устав караульной службы). Агент читает только спеку модуля, в котором работает: правка в web/ подтягивает ~11 КБ, а не капабилити-файлы со всего дерева. Через четыре изменения на SlimSpec спеки модулей подросли до 4 файлов и 641 строки. Это всё ещё на 78% меньше, чем было у OpenSpec. Спеки растут, но растут как надо: вместе с кодом, а не вместе с бюрократией.
Сколько стоит одно изменение
Считал по транскриптам Claude Code. Токены здесь означают весь вход, который обработала модель (input + чтение кэша + запись в кэш), основная сессия и сабагенты вместе. Самая близкая по размеру пара:
OpenSpec (logcat-padded-tags)
SlimSpec full (iana-tz-hash)
Изменено кода
409 строк, 4 файла, 1 модуль
435 строк, 15 файлов, 3 модуля
Обработано токенов
45,7M
29,7M (−35%)
Токенов на строку кода
~110k
~68k (−38%)
Ревью
нет
2 раунда verify на глубине high, один реальный блокер исправлен
Закоммичено процессных файлов
~530 строк
0
Время с гейтами
91 мин
56 мин
И это при том, что SlimSpec успел больше: 5 вопросов по решениям, 3 гейта, 9 задач в 3 волнах, ground в 4 спеки, ADR и оба README. Блокер, найденный ревьюером, был паникой на крайних датах. Та самая ошибка, которая в проде вылезает ровно 31 декабря в 23:59. В прогоне OpenSpec ревью не было вовсе.
Стоимость изменения в токенах
На мелких изменениях то же самое. Два изменения на OpenSpec обработали 31,5M и 45,7M токенов, два на SlimSpec (fast и medium) 6,8M и 12,5M. Один implementer в OpenSpec в одиночку съедал 13–16M токенов, сабагент SlimSpec 0–1M: каждому достаётся одна узкая дорожка, и ему не нужно читать весь мир, чтобы поменять одну функцию.
Теперь оговорки, их лучше назвать самому, пока это не сделали в комментариях. n = 1–2 на подход, проект один. Статистики тут как в анекдоте про среднюю температуру по больнице. Мелкие изменения на SlimSpec были в 5–10 раз меньше по коду, так что часть разницы объясняется просто размером. Часть агентов SlimSpec работала на Sonnet или Haiku. А основная сессия full-прогона тащила посторонний контекст из более ранней работы, и это, наоборот, завышает её счёт. Так что цифры не бенчмарк, а наблюдение. Но наблюдение довольно громкое.
Что не взлетело по дороге
Гладко было на бумаге. Кое-что я сначала сделал иначе и потом переделывал.
Implementer на каждую задачу. Выглядело красиво: свежий агент, узкий контекст, чистота и порядок. На деле каждый холодный старт заново читал explore.md, спеки и код. Сколько задач, столько раз «здравствуйте, а что у вас тут за проект?». Теперь один implementer ведёт дорожку из связанных задач.
Worktree для изоляции в режиме full. Не взлетело, потому что worktree сабагента ответвляется от закоммиченного состояния и не видит незакоммиченных результатов прошлых волн. Вторая волна честно строила дом без первого этажа. Пришлось бы коммитить каждую волну. Оставил параллелизм по непересекающимся файлам в одном рабочем дереве.
Хотел хук, который не даёт править код без падающего теста. Звучит строго и надёжно. Но промпт-хук не может проверить, что red-прогон действительно был, а хуки плагина включены всегда, независимо от режима. Охранник, который не умеет проверять пропуска, но стоит у каждой двери. Проверка переехала в verify.
С настройкой вышла смешная история: сначала написал bash-визард. С менюшками, с вопросами, всё как у людей. Потом выяснилось, что скилл не умеет вести интерактивный скрипт, а ! в сессии работает без TTY. Визард получился красивый, но запустить его было нельзя. Сейчас /slimspec:init просто задаёт вопросы прямо в сессии.
И мелочь, которая раздражала каждый день: в explore вопросы шли строго по одному. Ждёшь круг на каждое решение, даже когда все вопросы известны заранее. Ощущение как в техподдержке: «ваш вопрос очень важен для нас, оставайтесь на линии». Теперь независимые идут пачкой, до четырёх за раз.
Чем пришлось заплатить
Ложки нашлись, но осадочек остался. Вот что ушло вместе с лишними артефактами:
Сценариев как готового списка тест-кейсов больше нет.
Обоснования отдельных изменений частично пропали. Что-то осталось в ADR, остальное только в git-истории. Если вы любите археологию по git log, вам понравится.
Самая большая спека модуля (~14 КБ) грузится целиком при любой работе в этом модуле.
Работает только с Claude Code. OpenSpec поддерживает 30+ AI-инструментов, Superpowers тоже работает со многими агентами и умеет кучу всего помимо спек: отладку, worktree, ревью. SlimSpec закрывает только spec-driven цикл и не притворяется швейцарским ножом.
Настройка под проект
Конфиг необязателен, у каждого ключа есть дефолт. Не хотите ничего настраивать? Не настраивайте, всё заведётся и так. /slimspec:init спросит всё в сессии и запишет .slimspec/config.yaml:
mode: medium # fast | medium | full
spec:
format: claude-md # claude-md | readme | central | native | none
unit: auto # auto (по билд-файлам) | glob директорий, напр. "src/*/"
adr: false # дополнительно вести решения в docs/adr/NNNN-*.md
test: auto # или явная команда
commit: none # none | lane | wave
apply:
agents: 3 # максимум параллельных implementer
review:
depth: auto # auto (по режиму) | low | medium | high
models: {} # модели по ролям: scanner, planner, implementer, reviewer, grounder
sourcecraft.dev
Пара слов о том, что тут не очевидно.
mode задаёт вес цикла. В fast explore и plan живут в одном файле, вопросов не больше трёх, implementer один, ревью на low. Это для «поменять текст кнопки и не сойти с ума». medium добавляет сканер, грилинг, планировщик и параллельные дорожки, ревью на medium. full сверху ставит явный гейт на explore.md и ревью на high, для изменений, после которых хочется спать спокойно. Можно вообще не выбирать: после скана /slimspec сам предложит режим по размеру изменения.
spec.format решает, где живут спеки. По умолчанию это вложенные CLAUDE.md. Можно README.md рядом с кодом, общую папку specs/ для фич поперёк модулей, нативные доки языка (Go doc.go, Rust //!, Python docstring, KDoc) или none, тогда ground пропускается. Для тех, кто живёт по принципу «код и есть документация».
spec.unit говорит, что считать модулем; auto находит границы по package.json, go.mod, Cargo.toml, build.gradle(.kts), pyproject.toml.
commit включает коммит после каждой дорожки или волны. Коммитит только основная сессия, агенты никогда. Пушить SlimSpec не умеет в принципе, и это фича: никаких сюрпризов в main в три часа ночи.
models раздаёт модели по ролям. По умолчанию сканер и implementer на Sonnet, а планировщик, ревьюер и grounder на Opus. Думать дорого, делать дешевле, вот и вся экономика.
Если проект уже сидит на OpenSpec или Superpowers, есть /slimspec:migrate-openspec и /slimspec:migrate-superpowers. Переносятся только спеки: каждая привязывается к модулям, сжимается и сверяется с кодом. Где код расходится со спекой, решаете вы, потому что иногда врёт спека, а иногда код, и угадывать тут нельзя. Старые файлы удаляются только после вашего подтверждения.
Вместо вывода
Сильным моделям не нужны тяжёлые спеки. Им достаточно подсказать, что делать и где искать, остальное они восстановят из кода быстрее, чем дочитают четыре артефакта. Токены, которые уходят на proposal, который никто не откроет, лучше потратить на следующую фичу. А ещё лучше на новый проект. Миллион токенов туда, миллион сюда, а в итоге набегает на ещё один пет-проект, который давно лежит в списке «когда-нибудь».
Если вы тоже упирались в медленный SDD-флоу, попробуйте SlimSpec на одном изменении и сравните со своим текущим процессом. Особенно интересно, как он поведёт себя в команде и на проектах крупнее моих. Пишите в комментариях или в issues, ругать тоже можно, только с цифрами.
SlimSpec на GitHub · Сайт
spec 駆動開発のツールはまだマスター設計を考えていない:機能ごとの設計書が作った端から枯れていく
AI に実装させる前に、機能ごとの設計ディレクトリ(要件・設計・タスク)を repo に置く。spec-kit や Kiro が広めたこの形は、2026 年 10 月時点でほぼ定番になった。
ところが、この形には「今のシステム全体の設計はどこにあるか」に答える場所が無い。設計書は機能ごと、変更ごとに作られ、merge されるたびに増えていく。それらを畳み込んだマスター設計、つまり「今の仕様はこれ」と言える 1 つの文書を、spec-kit も Kiro も持たない。AI は次の作業で、溜まった設計ディレクトリのどれかを今の仕様として読む。
知りたいこと
結論
根拠
なぜマスターが要るのか
機能ごとの設計書は差分の説明でしかない。差分を積んでも今の仕様にはならない
構造からの説明
今のツールはマスターを持っているか
spec-kit と Kiro は持たない。持つのは OpenSpec だけで、それも変更提案を通らないコード変更はマスターに戻らない
公式ドキュメント、spec-kit の issue #620・#4940
どの repo に置くか
どのツールも、既定では設計書をコードと同じ repo に置く。機密と読み手の違いを考えると、設計は専用の repo に分ける判断になる
構造からの説明、OpenSpec の Stores
自分たちで持つには
設計 repo に提案とマスターを置き、コードの PR から ID で参照させる
設計の提案
2026 年 10 月時点の主なツールを並べると、次のとおりである。
ツール
機能ごとの設計書
マスター設計
コードの変更がマスターに戻るか
設計を別の repo に置くには
spec-kit
specs/NNN-name/
無い。維持の方式は「チームの選択」
戻す core コマンドは not planned
プロジェクトはディレクトリ単位。別 repo の間は版付きの成果物か同期したコピーで、と案内するだけ
Kiro
spec ごとに requirements・design・tasks
無い。steering は前提の説明
手順なし
multi-root workspace で、別フォルダの .kiro/ の spec も一覧に並ぶ
OpenSpec
openspec/changes/<名前>/
openspec/specs/
変更提案を通ったものだけ
Stores(ベータ)で設計専用の repo を持てる。同期はツールの外
機能ごとの設計書は「その時点の差分の説明」
機能ごとの設計ディレクトリに書かれているのは、「今の状態から、この機能でこう変える」という差分の説明である。merge した時点で、その差分はコードに入り、役目を終える。
差分を何本積んでも、今の仕様にはならない。たとえば、001 でメールとパスワードのログインを作り、9 か月後の 009 で二段階認証を足したとする。今のログインの仕様を知るには、001 と 009 を両方読んで頭の中で合成しなければならない。その間にレビューの手直しや障害対応でコードだけ変わっていれば、どちらの設計書にも書かれていない。
人間なら、古い設計書を「経緯の記録」として読み流せる。AI はそうはいかない。repo に specs/001-login/spec.md があれば、それを今の仕様として読み、その前提でコードを書く。
設計書を artifact や Wiki ではなく repo に置けば、「コードと同じ PR で直せる」「履歴が残る」「AI がファイルとして読める」は手に入る。ただ、機能ごとの設計書が溜まるだけなら、AI が古い設計を正として読む事故は、置き場所を変える前と同じ形で起きる。要るのは置き場所ではなく、マスターである。
spec-kit:マスターは「チームの選択」
spec-kit の成果物は、機能ごとの specs/NNN-name/(spec.md、plan.md、tasks.md など)と、全体の原則を書く constitution.md である。constitution はテストの方針や設計原則を書く場所で、システムが今どう振る舞うかを書く場所ではない。
全体の今の仕様を持ちたい、という声は早くから出ている。2025 年 9 月に立った issue #620 は、まさに先の 001 と 009 の例を挙げて「仕様を時間とともに統合する推奨のやり方はあるか」と尋ねている。2026 年 10 月時点でも open のまま、「全体の今の定義を 1 か所で持ちたい」というコメントが続いている。
公式ドキュメントの答えは、Spec Persistence Models にある。配信後の設計書の扱いを flow-forward(完了した設計書は履歴として残し、変更は新しいディレクトリで行う)、living spec(機能の spec.md を契約として更新し続ける)、flow-back(実装で得た発見を設計書に戻す)の 3 つに分け、こう書いている。
None is the default, and none is required by Spec Kit.
living spec でも、更新し続けるのは機能ごとの spec.md である。機能をまたいで今の仕様を 1 つにまとめる場所は、どの方式にも無い。
2026 年 10 月 13 日には、実装との食い違いのうち「コードが正しい」ものを spec と plan に書き戻す core コマンドの提案(#4940)が出た。これは同じ日に not planned で閉じられた。メンテナの説明は「配信と、配信後の維持は別物である。維持の方式はチームが選ぶもので、core がコマンドを用意する約束はしない」というものだった。
一方で、設計思想を書いた spec-driven.md にはこうある。
Specifications stay in sync with code because they generate it
spec がコードを生成するので同期は保たれる、という主張である。これは機能ごとの spec と、そこから生成したコードの間の話で、マスターの話ではない。「同期する」という言葉が、全体の今の仕様はどこにあるかという問いを見えなくしている。
コミュニティには、merge 後に機能の設計を中央の .specify/memory/spec.md に畳み込む archive 拡張がある。マスターを欲しがる人が自作している、というのが 2026 年 10 月時点の状態である。
Kiro:steering は設計ではない
Kiro の設計書も spec ごとに作られる。1 つの spec が requirements.md(または bugfix.md)、design.md、tasks.md を持つ。
全体の文脈として、Kiro には .kiro/steering/ がある。標準の 3 ファイルは次のとおり。
product.md:製品の目的、対象ユーザー、主な機能、事業の目標
tech.md:フレームワーク、ライブラリ、開発ツール、技術的な制約
structure.md:ファイル構成、命名規則、import の書き方、アーキテクチャ上の判断
どれも、AI にプロジェクトの前提を伝えるためのものである。「ログインは今どう振る舞うか」を書く場所ではない。
発表記事(2025 年 7 月 14 日)は「Kiro's specs stay synced with your evolving codebase.」と書いている。公式ドキュメントで同期の手段として挙がっている Sync Files は、設計を直したあとにタスクを作り直すことと、実装済みのタスクに完了の印を付けることをする。どちらも 1 つの spec の中の話で、spec をまたいで今の仕様をまとめる機能ではない。
唯一:OpenSpec はマスターを持っている
OpenSpec は、マスターを最初から設計に入れている。spec-kit の #620 にも「それがまさに OpenSpec の売りだ」というコメントが付いている。
openspec/specs/ を source of truth(今の振る舞い)とする。
変更は openspec/changes/<名前>/ に提案として置く。spec には差分(ADDED / MODIFIED / REMOVED)だけを書く。
/opsx:archive で差分をマスターに merge し、提案は changes/archive/ に凍結する。
「変更提案は凍結し、今の仕様は 1 つだけ更新し続ける」という分け方で、RFC や ADR を運用してきたプロセスと同じ構造である。
ただし、マスターが更新されるのは、変更提案を通ったときだけである。手でコードを直したときは「archive の前に揃える」と FAQ にある。食い違いを見つける /opsx:verify は任意で、Verify won't block archive と明記されている。verify の対象は 1 つの change で、change を作らずに直したコード(レビュー後の手直し、障害対応、リファクタリング)を、マスターと突き合わせる仕組みは無い。
設計の repo をコードの repo から分ける
マスターをどこに置くか。spec-kit は specs/、Kiro は .kiro/、OpenSpec は openspec/ と、どのツールも、既定では設計書をコードと同じ repo に置く。同じ PR でコードと設計を直せるので、ずれを防ぐには一番強い置き方に見える。
しかし、設計をコードの repo に置くと決める前に、2 つの点で設計 repo を分ける判断が要る。
機密:読める範囲は repo 単位でしか切れない
設計の背景には、コードの repo に入れられないものが混ざる。
特定の顧客の要望、契約条件、障害の相手先
料金や取引の事情、まだ公表していない計画
個人情報を含む問い合わせの中身
GitHub の読み取り権限は repo 単位である。「この repo のコードは読めるが、specs/ の下は読めない」という設定はできない。コードの repo に設計を置いた時点で、その repo を読める全員、つまり開発者全員、外部の協力者、CI、AI エージェントが背景まで読む。エージェントは読んだものを、コード、コメント、コミットメッセージ、PR 本文に書き出しうる。
背景を書かせないと、設計書は「AI は issue の背景を知らない」という元の問題に戻る。背景を書かせて、読める範囲を絞りたいなら、設計を別の repo に置くしかない。
読み手:設計を承認する人はコードの repo にいない
設計を「これで合っている」と承認するのは、PdM や顧客の窓口であることが多い。この人たちは、コードの repo に入る必要がない。設計がコードの repo にあると、承認のためだけにコードの読み取り権限を渡すことになる。
spec-kit は、この読み手の違いには気づいている。/speckit.specify の指示には、spec.md は「何を・なぜ」に絞り、開発者ではなく事業側の関係者に向けて書く、とある。ただ、その spec.md はコードの repo の中にある。事業側の関係者が読むには、コードの repo の権限が要る。
画面も同じである。人が意図を確かめるのは、文章より画面の画像である。merge 時点の画面を画像で固定して設計に添えると、コードの repo の履歴に画像が積み上がっていく。設計の repo なら、そこは気にしなくてよい。
分けると何を失うか
分けると、「同じ PR でコードと設計を直せる」が消える。2 つの repo は別々に merge されるので、何もしなければ、設計を artifact や Wiki に置いていたときと同じ形でずれる。分けるなら、このずれを塞ぐ仕組みを先に用意する必要がある。
Kiro は multi-root workspace で、複数のフォルダの .kiro/ にある spec を 1 つの一覧に並べて読める。設計用のフォルダを別に開いておく使い方はできるが、両者をつなぐ仕組みは無い。設計専用の repo を正面から扱っているのは、OpenSpec の Stores(2026 年 10 月時点でベータ)だけである。ドキュメントの説明は「planning in its own repo」で、複数の repo にまたがる機能や、要件を持つチームと使うチームが違う場合を動機に挙げている。機密や承認者の範囲は動機に入っていない。そして、2 つの repo の同期はツールの仕事ではないと明記している。
OpenSpec never clones, syncs, or pushes anything on its own.
マスターから設計する
2026 年 10 月時点のツールがマスターも repo の分け方も考えていない以上、チームが先に決めるしかない。順番は、機能ごとの設計書の書式より先に、マスターをどの repo に置くかである。
1. 設計 repo を作り、変更提案とマスターをそこに置く。 issue ごとの提案(背景・設計・手順)と、今の仕様を書くマスターを、同じ設計 repo に置く。読み取り権限は、背景を読んでよい人に絞る。PdM や顧客の窓口は、この repo だけに入れる。画面は merge 時点の画像で固定し、ここに置く。
2. 提案は merge の時点でマスターに反映し、凍結する。 AI への指示(CLAUDE.md や AGENTS.md)に「今の仕様はマスターを読む。提案は経緯として読む」と書けば、エージェントの読み方が一意に決まる。マスターの記述が変わらない小さい修正には、提案を要求しない。
3. コードの PR から、設計 repo を ID で参照させる。 同じ PR で直せない分は、CI で塞ぐ。コードの repo の PR には、次のどちらかを求める。
設計 repo の提案の ID を書く。CI は、その提案が承認済みかを確かめる。
PR 本文で「仕様は変わらない」と宣言する。
逆向きも見る。設計 repo の提案を凍結するときは、対応するコードの PR が merge 済みかを確かめる。提案を通らないコード変更がマスターに戻らない問題は、ツールの中だけで閉じている OpenSpec でも残っている。repo を分けるなら、この往復の検査が無いと必ずずれる。
4. AI には作業ごとに必要な分だけ渡す。 コードの repo で動くエージェントに、設計 repo 全体を読ませない。その作業の提案と、マスターの該当箇所だけを渡す。背景のうちコードに書き出してはいけないものは、提案の中で分けておく。
spec 駆動のツールは、1 つの機能を書き始めるまでを速くした。機能が積み上がったあとに「今の仕様はどこか」に答えること、そして「設計を誰に読ませるか」を決めることは、まだツールの仕事になっていない。設計を repo で持つと決めたら、どの repo に置くかと、コードの repo とをつなぐ検査も一緒に決める必要がある。
参考
github/spec-kit: spec-driven.md
github/spec-kit: Spec Persistence Models
github/spec-kit: Evolving Specs in Existing Projects
github/spec-kit: Using Spec Kit in a Monorepo
github/spec-kit #620: How to keep specs consistent and up-to-date with spec-kit?
github/spec-kit #4940: Core flow-back step for drift where the code is ahead of the spec
github/spec-kit Discussion #1804: How do you keep your spec files canonical?
Introducing Kiro
Kiro: Steering
Kiro: Specs best practices
Kiro: Multi-root workspaces
OpenSpec: Concepts
OpenSpec: FAQ
OpenSpec: Stores: Plan in Its Own Repo
Mentions
Why I Run My Coding Agent Inside a Devcontainer --- title: "Why I Run My Coding Agent Inside a Devcontainer" published: true description: "I limit what Claude Code can touch to the inside of a container, so I can use auto mode without worrying, and I use named volumes to decide which environment reads and which one writes." tags: devcontainer, docker, claudecode, ai canonical_url: fukurou.kompiro.dev cover_image: fukurou.kompiro.dev --- I do almost all of my development inside a devcontainer. Visual Studio Code opens a container, and I run Claude Code inside it. When I had Claude Code make the demo GIF for my README, the whole recording happened inside the container too. I started using devcontainers long before coding agents came along. My reason for using them has changed since then. Now it is that I can decide how far an agent reaches, one container and one volume at a time. This post describes where I draw those lines. How I got started with devcontainers will be a separate post. Summary 1. Keeping an agent's reach inside a container lets me use auto mode without worrying. The agent is cut off from my browser sessions and API keys, and experimental tools never land on the host. 2. Named volumes let me separate the environment that reads from the one that writes. In the OpenSpec setup I'm trying on my own, the spec container reads the code under development, and the development containers read the specs. 3. I don't recommend devcontainers to everyone. They can be tuned in fine detail, so there is a lot to learn. Fixing the configuration, though, is something you can hand to an agent. Keep secrets and experiments out of the agent's reach I have three reasons for keeping the agent inside a container. The first is to make it easy to try development tools. Tools around coding agents come and go quickly, and I often want to try something experimental. I'd rather not install those tools on my Mac. If they live in a container and don't work out, I can just rebuild the container. The second is to keep secrets out of reach. My browser on the host has plenty of logged-in sessions, and the host also holds various API keys. This is also why I chose Playwright inside the container over computer use when making the demo GIF. The third is accidental file deletion. I hear about it less these days, but I did hear several stories of agents deleting files. If only the files inside the container are in play, the damage stays inside that container. With all three in place, I can use auto mode without worrying. Even when the agent asks me for confirmation less often, I still know what it can touch. There is one hole I leave open on purpose. Claude Code's configuration directory (~/.claude) is bind-mounted from the host. That way the container can use the authentication I completed on the host, and I can look back across the sessions of every project later. Use named volumes to decide who reads and who writes Once environments live in separate containers, some things need to be shared between them. I connect them with named volumes. In repositories that use compose, devcontainer.json points at a compose file through dockerComposeFile, and that file refers to a network and volumes created outside the project. By default, Docker Compose creates a project and a network for each compose file. Bringing a whole project up or down is convenient, but you can't rebuild just one service. So I manage networks and volumes separately from the projects. The simplest thing to share is credentials. In this blog's repository, the GitHub CLI and dev.to credentials live in named volumes. "mounts": [ "source=gh-config,target=/home/node/.config/gh,type=volume", "source=devto-config,target=/home/node/.config/devto,type=volume" ] The volumes outlive the container, so rebuilding it doesn't mean logging in again. At the same time, the credentials stay off my Mac and out of the repository. The source code itself lives in a named volume too. Bind mounts on a Mac are slow. With the code in a volume, another container can see the same code just by mounting that volume. Example: a spec container that only reads the code On my own, I'm trying out OpenSpec. OpenSpec is a tool for writing the spec before the code, and it accumulates change proposals (called changes) in a spec repository. Writing a change requires reading the existing source code. I also wanted the agent to read the code as it currently stands in development. So I mount the volume that holds the development container's source code into the spec container as well. The agent in the spec container doesn't get to rewrite that source code. In the spec container's Claude Code settings (settings.json), the source code volume is not listed in additionalDirectories. The agent that writes specs only reads the code. There is also a mount in the other direction. The development containers mount the spec volume. That lets the development side check how the specs are progressing. The backend and the frontend are developed independently in their own containers, and both see the same specs. | Container | Mounts | What the agent writes | | --- | --- | --- | | Spec | The spec volume and the volume with the code under development | Specs only | | Backend development | The backend source code and the spec volume | Backend code | | Frontend development | The frontend source code and the spec volume | Frontend code | Containers decide what an agent can touch, and volumes decide which environment reads and which one writes. With the read and write directions set per container, I can run several agents side by side without them trampling each other's workspaces. Keep the production image minimal and bring your own tools There is also a line around what goes into the container. The image I ship to production should contain only the files the service needs to run. A development environment, on the other hand, needs room for whatever tools help me develop. So I build on the production Dockerfile and add development tools with devcontainer features and dotfiles. I manage dotfiles with yadm and tool versions with mise. One reason I bring my dotfiles into the container is worktrees. Developing with agents means using a lot of worktrees. For reopening and switching between them, I want the tools my hands already know, such as fzf. The work may happen inside a container, but the environment I operate by hand should feel the same as always. Devcontainers are not for everyone Devcontainers have their annoyances. Changing devcontainer.json means rebuilding the container. Every small tweak means waiting for a rebuild, so I'm careful when I edit it. Disk usage doesn't bother me. They also limit your choice of editor. Newer IDEs built for AI agents, such as Orca, are awkward to combine with devcontainers. That said, the Claude Code extension for Visual Studio Code is improving quickly too. Would I recommend devcontainers to everyone? No. They can be tuned in fine detail, which makes them hard to use casually, and beginners have a lot to learn. Still, if you ask Claude Code or Codex to fix your devcontainer configuration, they do a good job. If you want your development environment as code that you can reproduce, I do recommend them. Takeaways I keep using devcontainers because they let me decide, with containers and volumes, how much I hand to an agent. Inside a container, the agent can work in auto mode while my secrets and experimental tools stay separated from the host. Connected by named volumes, environments can share the same code and specs while keeping the reader and the writer apart. The OpenSpec setup is still an experiment. For a while, I'll watch how splitting the spec and development containers changes the way I write and work through changes.
OpenSpec 1.16 (30.10.) warnt bei Szenarien ohne GIVEN/WHEN oder THEN; mit --strict schlägt die Prüfung fehl. Für KI-Coding sinnvoll: Schon die Spezifikation braucht eine Ausgangslage und ein erwartetes Ergebnis. github.com/Fission-AI/OpenSpec/releases/tag/v1.16…
BMAD Method (Part 1): Spec-Driven Development Where the Human Stays in Control --- title: BMAD Method (Part 1): Spec-Driven Development Where the Human Stays in Control series: BMAD Method description: Why I care about spec-driven development whatever the framework, and how BMAD handles both a single change and a product from scratch around a human-approved intent. tags: ai, bmad, specdrivendevelopment --- As a software architect and senior software engineer, I keep watching the same change happen in the way we build software. In the first series I wrote about GitHub Spec Kit, and I stayed on one idea that I still think matters most: spec-driven development (SDD). Write the intent first, make it explicit, let the agent build against it, then check the result against what was written. That idea does not depend on a framework. Spec Kit is one way to apply it, BMAD Method is another, and a markdown file in your repo is a third. In this series I look at BMAD Method, and in this first article I stay on the concepts and the commands. I do not show a finished result yet. My angle is the same as before: not how fast an agent writes code, but who decides what gets built and who answers for what is produced. I think this is the question the industry is starting to ask. Anthropic has been talking about an AI Native Playbook, and BMAD has been moving in that direction for a while. This is a personal view, not a verdict. What Is Spec-Driven Development? Let's start from the problem. Many developers have had the same experience with an AI coding tool. The agent writes code quickly, the code often runs, and yet nobody on the team can say why it was written that way. Two sessions later the intent is gone, buried in a chat history, and the next change starts from a guess. I call this vibe coding. I do not think the problem is the model. The problem is where the context lives. If the intent exists only in a prompt, it disappears when the session ends. If it exists in a document that the agent reads and the human reviews, the team can inspect it, change it, and keep it. SDD, for me, comes down to four points: - The intent is written down before the code. In a file, not in a chat. - The agent works inside that intent. It does not reinterpret it silently. - The human approves the intent and judges the result. The agent does not own the definition of done. - The spec is versioned with the code. When the intent changes, the change is visible. As in the first article, I would say the rigor of the spec can vary (spec-first, spec-anchored, spec-as-source), and these four points hold at every level. Mental Model: the framework is a way to apply the idea at scale, not the idea itself. !Image description <!-- IMAGE 01 (done, images/01 png, source svg alongside): Diagram with four boxes in a row: "Intent (written)", "Spec (reviewed by human)", "Code (built by agent)", "Result (judged by human)". Under the first and last box, a label "human responsibility". Under the middle one, "agent works inside the spec". Clean, minimal, two colors. --> BMAD in a Nutshell BMAD stands for Breakthrough Method of Agile AI-Driven Development. It maps familiar roles (analyst, product manager, UX designer, architect, developer) onto AI agents, and it keeps the work in documents that the agents read and the humans review. Two ideas matter most for me. The first is that each document has one owner and one writing skill. The Product Requirements Document (PRD) is the source of the product definition, and nothing else claims to define it. The planning docs say that documents are "contracts between people first and input to the skills second". The second idea is a rule: nothing downstream reinterprets the PRD. If a story needs an answer the PRD does not have, the answer goes into the PRD first, and the derived documents are regenerated. The other thing BMAD gives you is more than one path. The first decision is about size, not tools. The build documentation says a change of roughly 500 lines, across a few files, fits one build session. The planning guide asks the question from the other side: is the intent already well defined? If it is, you hand it to a build, or to the epics and stories skill when the work is bigger. If it is not, you use the analysis skills first, in any order, until it is. The planning skills write the requirements down; they do not decide what you want. Trivial, you review it yourself: edit directly, no process One session (about 500 lines): intent -> /bmad-build -> result Epic-sized: intent -> brief, PRD, UX, architecture, epics and stories -> one /bmad-build per story -> retrospective Project-sized: several epics, shared decisions first, then the epic path for each !Image description <!-- IMAGE 02 (done, images/02 png, source svg alongside): Decision tree. Start node: "Is the intent well defined?". "No" branch to "Analysis skills (brainstorming, forge idea, brief, PRFAQ)" looping back. "Yes" branch to "How big is the change?" with four exits: Trivial -> "Edit directly"; One session -> "/bmad-build"; Epic-sized -> "Plan, then /bmad-build per story"; Project-sized -> "Several epics, shared decisions first". --> BMAD also names its skills by phase. The planning guide groups them as Analysis, Planning and Solutioning, and Build is the phase that follows (the older dev.to articles call it Implementation). Analysis is optional, and its skills run in any order. Planning is where the PRD and the UX documents are written. Solutioning is where the architecture is decided, and where the epics and stories and the sprint status are produced. Build takes one story at a time. I use these four names in the rest of the article. One note: the skill catalog of the version I have installed (6.12.4) labels its skills only plan and ship, so the four names are the guide's grouping, not a label you will see in the tool. !Image description <!-- IMAGE 03 (done, doc/article/images/03-bmad-phases.png): four colored columns, Analysis -> Planning -> Solutioning -> Build, each with its skills and the files it produces. Groups from docs.bmad-method.org/plan/choose-a-planning-path/; skills of the installed BMAD 6.12.4 (epics, sprint planning, code review, retrospective). --> Mental Model: size the process to the work, and make sure the intent is clear before anything is built. Setting Up The version I have installed is BMAD 6.12.4, the stable one. It installs from the project directory with one command: npx bmad-method install The installer sets up the modules and the skills for the coding tool I choose (Claude Code in my case). It writes the skills into .claude/skills/ and a _bmad/ folder with the configuration. In Claude Code the skills are typed in the slash form (/bmad-build, /bmad-prd), and that is the form I use in this article. When I am unsure where to start, there is /bmad-help. The online docs now describe a newer v7 preview, installed with the Skills CLI, with some different names (for example a product owner skill called bmad-agent-po). I follow the version I use, and I say where the docs differ. A Simple Example: a Todo List I use the same todo list as in the Spec Kit series, so the two approaches can be compared on the same problem. There are two situations, and they lead to two different paths. In both I show the commands and not the results. Path One: Adding a Flag to a Todo List I Already Have Suppose the todo list is already implemented, with add, edit and delete. I want to add a "done" flag to each item and toggle it from the list view. The change is small, clear and low risk, and it fits in one session. This is the short path, and for this path I need only one skill: bmad-build. It takes an intent, investigates, plans, implements, reviews, and fixes what it finds. Below is the flow from the build documentation, redrawn in my own style with the same structure (source: docs.bmad-method.org/build/build-a-change/). I walk through it node by node, because each node is a decision that somebody has to own. !Image description <!-- IMAGE 04 (done, doc/article/images/04-build-flow.png, editable source 04-build-flow.svg): the build flow of docs.bmad-method.org/build/build-a-change/ redrawn with the same nodes, loops and labels in a different style. Keep the source in the caption. --> How to read the diagram. The main line runs from top to bottom: Initial intent, Clarify and route, Plan, Approved plan, Implement, the "Fits AC?" check, Review, Present, Result. Dashed lines show where a human takes part: the interview during clarification, the optional plan review, and the review of the result. A one-shot mode skips the planning nodes and goes from Clarify and route straight to Implement. The loops are the interesting part: a patch goes back to Review, a bad plan goes back to Plan, an intent gap goes back to Clarify and route, a rejected change goes to the bin (Void), and anything unrelated is deferred to a file. Step 0: Size the Work (is it one session?): For this change the answer is yes: a few files and far fewer than 500 lines. The docs give the rule. If it fits, use bmad-build. If it is too big, plan first. If you are unsure, ask bmad. A trivial change that you will review yourself does not need the process at all, and I would not use it for a one-line typo. Step 1: Start a Fresh Chat (no shared context): I open a new chat in the AI IDE. The docs warn that reusing a session from another workflow can mix contexts, and in my experience that is where wrong assumptions come from. A fresh chat means the agent starts from the files, not from what we said about the previous feature. Step 2: Give the Intent (rough is fine): /bmad-build Add a "done" flag to each todo item, toggle it from the list view, and keep the state after reload. This is the Initial intent node. The docs say the intent can be rough, and it can come before, with, or after the command. It can also be an issue link, or a story from the epics list (/bmad-build story 2.3 builds story 3 of epic 2, and I use that form in Path Two). I prefer to write the intent in full for a change like this one. A rough intent is allowed, but it moves the cost to the questions the agent asks later. Step 3: Clarify and Route (resolve the intent from evidence): This is the Clarify and route node. The agent reads the codebase and any planning documents. Clear requests go ahead without a turn of questions. Anything the repository cannot settle becomes an open question on a finished design, not an interview before work starts. The human part is to answer those questions carefully, because wrong answers here are the costliest to fix later. In the todo case, I would expect a question about whether "done" items stay in the list or move to a separate view. That is my decision, not the agent's. Step 4: Plan and Approve (the optional gate): The agent evaluates the settled design on three facts: intent gaps, irreversible actions, and the footprint of the change. If all three are clean, it takes the light path: a minimal plan and the implementation in the same session, reviewed afterwards. If anything is flagged, it writes a full plan, and each intent gap becomes a question I must answer before approval. I approve the plan if it describes the right thing, and I push back if not, because fixing the plan is cheaper than fixing the code. For the todo flag, I would expect the light path. If the agent flags a migration of the stored data, the plan is where I decide it. Step 5: Implement, Check, Review (the agent's own gates): The Implement node is the agent's work. The "Fits AC?" check compares the change with the acceptance criteria that the build plan recorded. Then the Review node starts, and the agent reviews its own work with independent reviewers. The diagram names three lenses: - Blind Hunter: finds problems without the bias of the implementation context. - Edge Cases Hunter: looks for forgotten corner cases. - Verification Gap Finder: asks whether the tests really cover the change. The review ends in a triage, and the diagram shows where each outcome goes. A patch fixes issues that belong to this change and returns to Review. If the code is wrong because the plan was weak, the flow returns to Plan. If the plan is wrong because the goal was wrong, it returns to Clarify and route. A rejected change goes to Void. Unrelated pre-existing issues are deferred to deferred-work.md (the diagram spells the name with an underscore, the file in the project uses a hyphen). Then the agent commits locally, and runs the test suite if the project has one. I like that the loops are explicit. A review that can only say fixed or not fixed hides the cause of the problem, and here the cause has to be named. Step 6: Present and Review the Result (the human gate): The Present node is the agent's short summary, with next steps: create a pull request, walk through the change, or make another change. The Result node is mine. I run the walkthrough or skim the diff, I tell the agent what to fix (it can iterate in the same session), and when I am satisfied I ask it to push the commit and open the PR. Two things can still go wrong after this step, and I think it is worth being clear about both. If the change turns out to be wrong after I accepted it. The agent works on my local copy and commits there. If I pushed that commit and then find a problem, the way back is the ordinary one in git: undo the commit with a new commit, so the history stays intact and nobody has to rewrite what is already shared: git revert HEAD HEAD is the last commit, so this creates a new commit that cancels exactly what the agent added (in our example, the "done" flag). I do not try to patch the problem inside the old chat. I start a fresh chat and run /bmad-build again, with the intent rewritten to say what I missed the first time (for instance: "the flag must survive a page reload"). This is the same idea as the rest of the article: the intent is the thing I correct, and the code follows it. This is a git practice that fits the flow, not a step that BMAD runs for me. What the agent chose not to fix. During review the agent can find a real problem that does not belong to the current change. It does not fix it silently and it does not drop it: it writes it into deferred-work.md (the DEFER outcome in the diagram). Each entry names the story it came from, a one-line summary and the evidence. I read this file after every run. It is a backlog written by the agent, and a backlog nobody reads is where problems go to be forgotten. Reading it is part of my responsibility as the human who controls the result: for each entry I decide whether it is a new change to run later, a note to keep, or something to drop on purpose. Path Two: Writing a Todo List From Scratch Now suppose there is no todo list yet. I want a todo app with due dates and filters, kept in the browser. This is no longer one change. It is a body of work with several build units, so one /bmad-build is not enough. The planning documents become the contract, and each step reads files that the previous step wrote. Every step runs in a fresh chat (/clear first). I show the real commands, and I name the files each step reads and writes. I do not show what is inside them: that is for the next article. !Image description <!-- IMAGE 05 (done, images/05 png, source svg alongside): Horizontal chain of ten boxes: "Brainstorm (optional)" -> "Brief" -> "PRD" -> "UX (optional)" -> "Architecture" -> "Epics and stories" -> "Readiness check" -> "Sprint status" -> "Build, story by story" -> "Retrospective". Under each box the file it writes: brainstorm-intent.md, brief.md, prd.md, DESIGN.md + EXPERIENCE.md, ARCHITECTURE-SPINE.md, epics.md, PASS/CONCERNS/FAIL, sprint-status.yaml, spec-N-M-*.md, retrospective. A dotted arrow from "Retrospective" back to "Build" labeled "next epic". --> Step 1: Brainstorm (optional, what and why, no technology): /bmad-brainstorming A simple todo list web app. Explore features, UX ideas and what must stay out of version 1. A coach runs the session in the stance I choose: facilitator (no ideas from the coach), creative partner (ideas traded) or ideate for me. It reads nothing, because the idea is in the command. It writes a run folder under _bmad-output/brainstorming/ with brainstorm-intent.md (my decisions, kept apart from the ideas the coach offered) and a .memlog.md. If the idea is still half-formed there are two more analysis skills, /bmad-forge-idea to pressure-test it and /bmad-deep-recon to research a competitor or a technology. A personal view, not a verdict: if I cannot write the intent in three sentences after this step, I am not ready for a PRD. Step 2: Product Brief (what and why, in one page): /bmad-product-brief Create a product brief for a simple todo list web app. Use the brainstorming result at _bmad-output/brainstorming/brainstorm-todo_list-<date>/brainstorm-intent.md as the main input and treat its "Decisions" table as settled. The skill asks whether I want to create, update or validate, and whether I take the Fast path or the Coaching path. It reads brainstorm-intent.md and writes brief.md, addendum.md (the depth that does not belong in the brief) and a .memlog.md, in _bmad-output/planning-artifacts/briefs/. Then, in a fresh chat, I validate it before moving on: /bmad-product-brief validate the brief at <brief path> Step 3: PRD (what to build, not how): /bmad-prd Create the PRD for the todo list using the brief at <brief path> and the brainstorming intent at <intent path>. Features in order: (F0) foundations and storage; (F1) the list: add, tick, delete; (F2) due dates, overdue sign and filters. The PRD is the source of the product definition, and every later document derives from it. The skill has three intents, create, update and validate, and a Fast path or a Coaching path. Functional requirements get stable ids (FR-1, FR-2, ...), and what the skill inferred is tagged [ASSUMPTION] so that I can correct it. It reads the brief, the addendum and the intent, and writes prd.md and a .memlog.md in _bmad-output/planning-artifacts/prds/. Validate and update are two more commands: /bmad-prd validate the PRD at <prd path> /bmad-prd update the PRD at <prd path>: <what to change> Edits belong in the PRD, not in the stories, so the documents derived from it can be generated again. This is the whole point of the design. Step 4: UX (optional, how it looks and how it behaves): /bmad-ux Create the UX documents for the todo list from the PRD at <prd path>. Simple, calm, keyboard friendly, one screen. The skill captures my vision and does not impose its own. It reads the PRD and writes two peer documents, DESIGN.md (how it looks) and EXPERIENCE.md (how it behaves), in _bmad-output/planning-artifacts/ux-designs/, with mockups when I ask to see options. It is optional: I would skip it only if I accept designing those details later, during the builds. A fresh chat validates it: /bmad-ux validate the UX documents at <ux folder> Step 5: Architecture (how, only where two builders could disagree): /bmad-architecture Create the architecture for the todo list from the PRD at <prd path>, DESIGN.md and EXPERIENCE.md at <ux folder>. Decide: front-end framework, where tasks are stored, the task data model, the testing strategy. The output is not a full technical document. It is a short architecture spine that records only the decisions that two units, built independently, could make in incompatible ways. The skill gives a decision a stable id (AD-1, AD-2, ...) only if the call is non-obvious and a real trade-off. In coaching mode it shows me the alternatives and I choose. In coaching mode it also writes SOLUTION-DESIGN.md, a plain-language companion for people who read the project without building it (the spine wins if the two differ). It writes ARCHITECTURE-SPINE.md, that companion and a .memlog.md in _bmad-output/planning-artifacts/architecture/. This is where my review matters most, because a wrong shared decision spreads to every story: /bmad-architecture validate the architecture at <architecture path> Step 6: Epics and Stories (work cut by user value): /bmad-create-epics-and-stories Create the epics and stories list from the PRD, UX documents and architecture. Create exactly three epics, in this order: Epic 1 Foundations; Epic 2 Task list; Epic 3 Due dates and filters. Every story needs acceptance criteria. It reads the PRD, the UX documents and the spine, and writes one file, _bmad-output/planning-artifacts/epics.md. Every functional requirement is mapped to an epic, and every story has acceptance criteria in the Given, When, Then form and fits one build session. I check the epic and story numbers, because every build command from now on uses them. Step 7: Readiness Check (the gate before the build): /bmad-sprint-planning check implementation readiness The skill reads the planning documents the way a skeptic reads a handoff, and answers PASS, CONCERNS or FAIL. On CONCERNS or FAIL I fix the planning documents (/bmad-prd update, /bmad-ux, /bmad-architecture, or /bmad-create-epics-and-stories again) and run the check again. If something major changes later, there is a command for that too: /bmad-correct-course <description of the change> Step 8: Sprint Status (one file that says where every story is): /bmad-sprint-planning run sprint planning It reads epics.md and writes _bmad-output/implementation-artifacts/sprint-status.yaml, with every epic, story and retrospective as a key. All stories start as backlog, then move to ready-for-dev, in-progress, review and done. Step 9: Build One Story at a Time (the implementation phase): /bmad-build story 1.1 /bmad-build does not pick the next story by itself: I give it the number each time, one story per fresh chat, in order. Each run follows the flow of Path One, with the diagram as the guide. It reads the story in epics.md, the architecture spine and, for UI work, DESIGN.md and EXPERIENCE.md. It writes the code, a local commit, a spec file for the story (spec-1-1-<slug>.md), an epic-1-context.md on the first story of the epic, and it appends what does not belong to the story to deferred-work.md. It also syncs sprint-status.yaml: the story moves to review. The agent does not close its own work: I review, and I decide when a story is done. An optional extra check, in a fresh context, is /bmad-code-review. I would not use the unattended build skill for the first stories: they set the patterns for the rest. Step 10: Retrospective (close the epic): /bmad-retrospective 1 When the stories of the epic are finished, the skill reads the evidence the epic left (the specs, the diff, the commits, the sprint status) and judges the epic against the criteria it set for itself. Every finding carries a source, and a claim with no source is dropped. The result is a retrospective with findings, action items and an acceptance decision. A failing epic never closes as quietly accepted. Looking at these ten steps together, the pattern is always the same. Each skill writes one document or one piece of code. Each document has one writer. Each gate has a human decision. The agent works inside the boundaries that the earlier documents set. What BMAD Writes to Disk So far I have shown commands. What makes the process work is the files, because each step reads what the previous one wrote. BMAD keeps two folders at the project root, and they have different jobs. - _bmad/ is the metadata. The installed version and modules, one row per skill, the user and project names, the output folders, the team overrides, and the script that writes the logs. It holds no deliverable. - _bmad-output/ is the handoffs. Every document a skill produces, in one run folder per document, plus the sprint status and the build specs. This is the layout BMAD leaves on disk for the todo list. <prj_root>/_bmad/ _config/manifest.yaml installed version, modules, coding tools _config/skill-manifest.csv one row per installed skill core/config.yaml user name, project name, languages, output folders bmm/config.yaml custom/config.toml team overrides, committed to the repo custom/bmad-build.toml facts every build session treats as context scripts/memlog.py the script that appends to the .memlog.md files <prj_root>/_bmad-output/ brainstorming/brainstorm-todo_list-<date>/ brainstorm-intent.md .memlog.md planning-artifacts/ briefs/brief-todo_list-<date>/ brief.md, addendum.md, .memlog.md prds/prd-todo_list-<date>/ prd.md, .memlog.md ux-designs/ux-todo_list-<date>/ DESIGN.md, EXPERIENCE.md, .memlog.md architecture/architecture-todo_list-<date>/ ARCHITECTURE-SPINE.md, SOLUTION-DESIGN.md (coaching mode), .memlog.md reviews/VALIDATION-REPORT.md epics.md implementation-artifacts/ sprint-status.yaml epic-1-context.md spec-1-1-create-the-project-with-the-quality-gate.md deferred-work.md Here is the handoff chain in one table: what each step reads, and what it writes for the next one. | Step | Reads | Writes | |---|---|---| | Brainstorm | nothing (the idea is in the command) | brainstorm-intent.md | | Brief | brainstorm-intent.md | brief.md, addendum.md | | PRD | brief, addendum, intent | prd.md | | UX | prd.md | DESIGN.md, EXPERIENCE.md | | Architecture | PRD, DESIGN.md, EXPERIENCE.md | ARCHITECTURE-SPINE.md, plus SOLUTION-DESIGN.md in coaching mode | | Epics and stories | PRD, UX documents, spine | epics.md | | Readiness check | epics.md and the documents behind it | PASS, CONCERNS or FAIL | | Sprint status | epics.md | sprint-status.yaml | | Build, per story | the story, the spine, UX documents for UI work | code, spec-N-M-*.md, epic-N-context.md, deferred-work.md, status moved to review | | Retrospective | the specs of the epic, git history, sprint-status.yaml | the retrospective and its decision | Each run folder also holds a .memlog.md. It is the memory of that document, an append-only log with one line per decision, assumption or change, written through the memlog.py script and never edited by hand. This is the shape of one (the lines are illustrative, for the todo PRD): --- topic: Todo List PRD updated: 2026-11-01T12:10 --- - (decision) Working mode: Fast path, entry point Vision + Features - (assumption) Selected filter survives a reload - (event) PRD finalized Three things follow from this design: - A fresh chat can continue. A step reads files, not the history of the previous chat, so I can close the session and resume tomorrow. - Every decision has a trace. The memlog says what was decided and why, and which assumptions are still open. - A change starts at the source. If a story needs an answer the PRD does not have, the answer goes into the PRD first, and the later steps run again. BMAD does not keep one log for all the sessions: each document has its own memlog. If I want the view across the steps (which session ran which skill, and what it read and wrote), I would keep a small file for it. !Image description <!-- IMAGE 07 (done, images/07 png, source svg alongside): Two columns. Left, "_bmad/": a small stack labeled "config, manifest, overrides, memlog.py". Right, "_bmad-output/": a row of document icons (brainstorm-intent.md, brief.md, prd.md, DESIGN.md + EXPERIENCE.md, ARCHITECTURE-SPINE.md, epics.md, sprint-status.yaml, spec-N-M.md) connected by arrows, each arrow labeled "read by the next step". Under each document a small ".memlog.md" tag. --> What the Method Gives You - Context that survives sessions. Decisions live in files, so a new chat starts from documents, not from memory. - Version control for decisions. The PRD, the architecture and the stories live in git, next to the code. - Predictability. I know the likely end state of a session, because it was written before the session started. - Several sizes of process. A one-session change and a whole product use the same vocabulary with very different amounts of ceremony. The other side, with the same sincerity as before: What the Method Does Not Give You - Correctness by default. An agent can implement the wrong thing precisely. A good spec reduces guessing, it does not remove it. - Zero overhead. For a typo or a CSS tweak, even the short path is too much. - Freedom from handoff problems. Agents with different roles can still make conflicting assumptions. The documents make the conflict visible, but a human has to resolve it. - Room in the context window. Specs, architecture and stories consume context, so they must stay concise. - A replacement for judgment. The framework tells you when to stop and ask. It does not tell you what the product should be. The Role of the Human In every path, the agent produces a lot, and the human is responsible for what is accepted. On the short path I answer the open questions, approve the plan when it is flagged, and review the result. On the long path there are moments where a human decision blocks the next step. These are the ones I meet in the version I use (the planning guide of the online docs lists five sign-off points for the newer version): | Moment | What I judge | What it blocks | |---|---|---| | Brainstorm intent | Which directions survive, the Decisions table | The brief and the PRD | | PRD validation | The findings report | UX and architecture | | Architecture validation | The decisions that are mine, the corrections | Epics and stories | | Readiness check | PASS, CONCERNS or FAIL | Sprint planning and the first build | | Plan approval and story review | The plan when flagged, the diff, deferred-work.md | Marking the story done | | Retrospective decision | Did the epic meet its criteria | The next epic | Each of these leaves a written trace, in a memlog, a report or a status file. In a regulated company that is the audit trail, and in a small team it is the best record of why a decision was made. I think this is the clearest statement of responsibility I have seen in an agent workflow. Mental Model: bounded autonomy, not full automation. !Image description <!-- IMAGE 06 (done, images/06 png, source svg alongside): Timeline of the from-scratch path with six human icons above: "brainstorm intent", "PRD validation", "architecture validation", "readiness check", "story review", "retrospective decision". Below it a band labeled "agent produces, human accepts or rejects". --> Takeaways 1. A spec is a contract between people first, and input for agents second. If the intent is not clear to the people involved, no agent will make it clear for them. Writing it down is where the work starts. 2. Size comes first. One session, one epic and one project need different amounts of process. BMAD gives me a single command for the small change and a planning path for the large one, and choosing between them is my call. 3. The loops in the build flow are the point. A bad plan, an intent gap and a deferred problem each go back to the layer that caused them. That is what keeps a wrong decision from being buried in the code. 4. The human approves the plan and judges the result, and the agent works inside both. The responsibility for what is produced does not move. What changes is where I spend my attention: on the intent, the gates and the diff. 5. The handoff between steps is a file, not a chat. That is what lets a fresh session continue, and what leaves a written trace of every decision. A change starts in the source document, so the later ones can be regenerated. What Comes Next BMAD is one answer to a question that many people are asking at the same time: how do we give an agent enough written intent to work well, and keep a human in charge of what comes out? I do not think it is the only answer, and I would not want this series to be only about one tool. In the next article I want to make the example more concrete. I also want to keep the radar on, because spec-driven development is moving fast: what the major players are doing about it, how the SDLC changes when an agent does part of the work, and which other approaches are worth exploring. Two that I already have on my list are OpenSpec by Fission-AI, and the agent-skills collection by Addy Osmani. I have not formed a view on them yet, and I would rather look before I write about them. There will be at least one more article after this one. Stay tuned. What is your experience with planning documents and agents? Do you keep the spec in the repo, in a tracker, or in the chat? I would love to read your experience in the comments.
SDD desde cero: cómo dejé de tirar código de Claude Code a la basura Hace unos meses tiré a la basura dos días de trabajo de Claude Code. No estaba mal hecho. Estaba muy bien hecho. El problema es que no era lo que hacía falta: le había pedido algo en una frase, se puso a programar y, cuando lo vi, ya era tarde. Desde entonces trabajo con SDD (Spec-Driven Development, desarrollo guiado por especificaciones). Este artículo es lo que me habría gustado leer al empezar: qué es, por qué cambia tanto con agentes de código y cómo probarlo en una tarde. El problema: el agente es rápido, pero no lee la mente Un agente de código hace en minutos lo que antes llevaba días. Pero trabaja con lo que entiende de un mensaje. Si el encargo era ambiguo, construye otra cosa, y te das cuenta al revisar el código, cuando ya hay mil líneas. Y hay un segundo problema que se ve menos: quien pidió el cambio (alguien de negocio, de soporte, un cliente) no tiene forma de saber cómo va. Pregunta en el chat, alguien mira el código, contesta «casi está». La idea: primero se acuerda, después se programa SDD es una regla sencilla: antes de tocar código, se escribe qué se va a construir y una persona lo aprueba. Con agentes, ese papel lo escribe el propio agente. Tú solo lo lees y dices sí o no. El malentendido sale antes de programar, cuando arreglarlo cuesta una frase, y no después. Las palabras que vas a oír - Requisito. Lo que tiene que poder hacer alguien cuando esté hecho, en palabras normales. «Quien gestiona descarga las facturas del mes en un fichero.» - Propuesta. El plan del agente: qué va a cambiar, por qué y qué queda fuera. - Criterio de aceptación. Cómo sabréis que está bien. «El fichero se abre en Excel con sus tildes.» Cada requisito tiene al menos uno. - Especificación. Cómo debe comportarse el sistema, escrito para que quede. El siguiente cambio parte de ahí. - Tareas. Los pasos del agente para hacerlo. - Aprobación. El sí de una persona. Sin él, el agente no programa. Un ejemplo de principio a fin 1. Marta pide algo: «Exportar las facturas del mes en CSV». Escribe tres requisitos: que quien gestiona pueda descargarlas, que se abran bien en Excel y que solo salgan las de su empresa. 2. El agente escribe la propuesta. Lee la tarea y escribe qué va a cambiar, qué queda fuera y cómo se comprobará cada requisito. 3. Alguien la aprueba o pide cambios. Hasta entonces, el agente no programa. 4. El agente programa y prueba, y al terminar comprueba cada criterio de aceptación contra lo acordado. 5. Marta lo ve llegar: cada requisito pasa de «sin empezar» a «en desarrollo», «probado» y «en producción». ¿No es más lento? Añade una parada: aprobar. En mi caso son cinco minutos leyendo mientras tomo mate. A cambio, se programa una vez lo acordado y no varias veces lo malentendido. No todo necesita SDD: un bug o una incidencia se arreglan y ya. SDD es para lo que cambia el comportamiento. Cómo probarlo esta tarde (sin herramientas de pago) La pieza base es OpenSpec, un formato abierto para que el agente escriba propuestas y especificaciones dentro de tu repositorio, en ficheros de texto. npm install -g @fission-ai/openspec@latest cd tu-proyecto openspec init A partir de ahí, en Claude Code le pides que proponga el cambio antes de implementarlo. Te deja en openspec/changes/ la propuesta, las especificaciones y las tareas. Lo lees, corriges lo que no cuadre y le dices que adelante. Con esto ya tienes el 80 %: el agente piensa antes de programar y tú decides con el plan delante. Lo que me faltaba (y por qué acabé construyendo algo) OpenSpec resolvía mi parte. Pero la propuesta vivía en el repositorio, y quien pedía el cambio no la veía nunca. La aprobación era «lo leí y dije OK en el chat», y nadie fuera del terminal sabía en qué punto estaba cada requisito. Por eso hice Atalaya, un gestor de trabajo (tareas, sprints, Kanban) con SDD dentro: los requisitos se escriben en la tarea, el agente informa su propuesta por MCP, una persona aprueba en la tarea (el agente no puede aprobarse solo) y cada requisito enseña su estado hasta producción. Las especificaciones siguen siendo ficheros de OpenSpec en tu repo: si un día lo dejas, se quedan contigo. Está en acceso anticipado y es gratis. Pero lo importante del artículo no es la herramienta, es la regla: que el agente proponga y una persona decida antes de que se programe. Empieza con OpenSpec a pelo y verás la diferencia. --- ¿Cómo lo hacéis vosotros? ¿Revisáis lo que va a hacer el agente antes, o el código después? Me interesa mucho saber qué os funciona.
AIと2週間で、問題7,000問の金融教育ゲームを作った開発プロセス【OpenSpec × Claude Code】 はじめに 新社会人向けのお金の学習ゲーム「マネラン」を、AIのコーディングエージェントと一緒に作っています。 給与明細・税金・社会保険・NISA・詐欺対策などを、1回3〜5分のクイズで学べる、Duolingo のようなアプリです。 最初のコミットから約2週間で、次のところまで来ました。 項目 数 コミット 106 完了した仕様変更(OpenSpec の change) 54 仕様(capability) 33 コース / ユニット / レッスン 17 / 72 / 713 問題 7,130問(8種類の出題形式) 用語集 417語 テスト Flutter 54ファイル、pgTAP 11ファイル、Edge Function・Web のテスト 構成は Flutter(iOS / Android / Web)+ Supabase(Auth・Postgres・Edge Functions)+ Next.js(LP と管理画面)です。 この記事では「AIに何を任せて、人は何をしたか」「どうすれば2週間でここまで進むのか」を、実際のリポジトリの中身を見せながら紹介します。 AIで開発してみたい人、AIに書かせたらコードが散らかって困っている人の参考になればうれしいです。 1. まず仕様書を書いて、AIに「地図」を渡す 開発を始める前日に、製品仕様書(docs/product-spec.md)を書きました。 誰のためか(MVPは入社1〜2年目の新社会人) 何を解決するか(「手取りがなぜ減るのか分からない」「詐欺の標的になりやすい」など) 何をしないか(金融商品の勧誘・個別の投資助言はしない、コインを現金に換えない) ゲームの仕組み(育つ貯金箱、間違えた問題が敵になる「ミスモンスター」、詐欺メッセージを見抜く「詐欺バスター」など) ポイントは「やらないこと」まで書くことです。 AIは頼まれていない機能も気を利かせて作りがちですが、スコープ外がはっきりしていると、提案がぶれにくくなります。 2. OpenSpec で「仕様 → 設計 → タスク → 実装」を1変更ずつ回す このプロジェクトの中心にあるのが OpenSpec です。 変更のたびに、次の4つの文書を AI と一緒に作ってから実装に入ります。 openspec/changes/<変更名>/ ├── proposal.md # なぜ・何を変えるか・影響範囲 ├── specs/ # 要件と受け入れシナリオ(WHEN / THEN) ├── design.md # 設計上の決定と、その理由 └── tasks.md # 実装タスクのチェックリスト 実装が終わったら archive して、変更の内容を正本の仕様(openspec/specs/)に取り込みます。 2週間で archive した変更は54件。1日あたり4件ほどのペースです。 2026-10-15-migrate-to-supabase 2026-10-16-add-challenge-mode 2026-10-17-add-marketing-site 2026-10-21-enhance-lesson-game-effects 2026-10-22-add-profile-image-upload 2026-10-25-add-mascot-answer-feedback 2026-10-27-add-slack-event-notifications ... なぜ「いきなり実装」させないのか AIに「〇〇を作って」と直接頼むと、それらしいコードはすぐに出てきます。ただ、規模が大きくなるにつれて次のことが起きます。 前に決めたこと(データの持ち方、命名、画面の余白)と違う実装が混ざる 「なぜこうなっているのか」が誰にも分からなくなる レビューする人が、差分のコードだけを見て判断しなければならない 先に proposal と design を書かせると、人がレビューするのは数百行のコードではなく、数十行の日本語になります。 方向がずれていれば、コードを書く前に直せます。 タスクには「どう確かめるか」まで書く tasks.md の各タスクには、完了の条件を具体的に書きます。たとえば Slack 通知を追加したときのタスクはこうです。 - [x] 2.3 supabase/tests/90_auth_notify_test.sql(pgTAP)で、判定関数が 2.1 の各経路を 正しく分類すること(確認前のメールは null、確認と同時のログインは登録だけ、 トークン更新は null、ゲストは null)と、Vault が無いときにトリガーが何もせず auth.users の更新が成功することを確かめて supabase/tests/run.sh が通る 「実装する」ではなく「〇〇のテストが通る」「ブラウザで△△を確かめる」で終わらせると、AIが自分で完了を判定でき、人の確認も楽になります。 3. AIへの「憲法」を1か所に書く OpenSpec の config.yaml には、すべての変更で守るべき前提を書いておけます。マネランではこう書いています(抜粋)。 context: | 成果物(proposal/specs/design/tasks)は日本語で書く アプリはFlutter(iOS/Android/Web)。ゲームのルールは純粋な Dart のドメイン層(app/lib/domain)に置く 利用者データの書き込みは RLS と Postgres 関数(RPC)で守る。複数の表にまたがる反映は1つの RPC(1トランザクション)で行う コイン・利息・ストリーク・XPの不正対策は、サーバー側の検証で行う。日付判定にはサーバー時刻(now())を使い、端末時刻を使わない 有料化(課金・プレミアムプラン・広告)は当面行わない 実在の金融商品・企業名・サービス名を学習コンテンツや詐欺ケースに使わない。投資助言・勧誘にあたる表現を入れない ここに書くのは「コードを読んでも分からない決定」だけです。 ファイル構成のようにコードを読めば分かることは書きません。逆に「端末時刻を信じない」「広告は入れない」のような方針は、書いておかないと AI は毎回それらしい別案を出してきます。 4. 大きな方針転換も、早いうちなら AI と一緒に一気にやれる 開発2日目に、バックエンドを Firebase から Supabase に移すと決めました。 理由は、週ごとのリーグ(昇格・降格)などのサーバー処理を安全に作るには、Firestore のルールだけでは足りなかったからです。本番のデータがまだ無く、移行のコストが最も低いタイミングでした。 この変更も、proposal で「なぜ今か」「何が BREAKING か」「どこに影響するか」を書いてから実装しています。 学習結果の反映を1つの Postgres 関数(apply_activity)にまとめ、学習日はサーバー時刻で決める 増分の上限・二重反映をサーバー側で検証する RLS で「本人と運営だけが読み書きできる」ことを pgTAP でテストする ゲームのルール(貯金箱の利息・ストリーク・XPの計算)は Flutter にも Supabase にも依存しない純粋な Dart の層に分けておいたので、ドメイン層は一行も変えずにバックエンドだけを入れ替えられました。 AI に任せる量が多いほど、こうした「変わりにくい部分」と「入れ替わる部分」の境目が効いてきます。 5. コンテンツ7,000問も AI と作る。ただし「質の基準」が先 問題は全17コースで7,130問あります。これを手で書くのは現実的ではないので、AI に下書きを作ってもらっています。 ただ、何も決めずに作らせると、次のような「AIっぽい問題」が大量にできます。 正解だけが長くて丁寧なので、読まなくても当てられる 誤答が「何も起きない」「請求額が半分になる」のように明らかにおかしい 正解がいつも「専門家に相談する」 そこで content/QUALITY.md に問題の質の基準を書きました。 誤答の選択肢 誤答は、実際によくある誤解・ありがちな計算ミス・似た制度との取り違えから作る。 - よい例(数字): 正しい計算で使わなかった値・時価と簿価の取り違え・年と月の取り違え・旧制度の数字 - 正解だけが長い・丁寧・「確かめる」「相談する」で終わる、という形で正解が分かってしまわないようにする - 「専門家に相談する」を正解にするのは、本当に個別の判断が要る場面だけ さらに、形式のルール(1レッスン10問、問題タイプ3種類以上、難易度の配分、用語集にない用語を使わない など)は、content/tools/validate_content.py で機械的に検証します。 「質」は文章で基準を渡し、「形式」はスクリプトで検証する。この2段構えで、量と質を両立させています。 一斉にやらせない コンテンツを大きく書き直すとき、最初は複数のコースを並列で一斉に AI に任せていました。結果は、コースごとに基準の解釈がばらつき、見直しが追いつかなくなりました。 今は「1コース書き直す → 検証 → 人が読む → 次のコース」と順番に進めています。 AI は並列にいくらでも動かせますが、ボトルネックは人のレビューです。レビューできる速さに合わせるほうが、結局早く終わります。 なお、お金の制度は改定されるため、問題はすべて下書き扱いにし、FP などの専門家の監修を経て公開する流れにしています。AI が書いた専門的な内容を、そのまま「正しいもの」として出さないためです。 6. デザインの統一も「仕様」にする UI の改善も OpenSpec の変更として扱っています。 unify-page-margins(全画面の余白をそろえる) vibrant-gold-theme → unify-dark-game-theme(色をトークンで一元管理する) redesign-badges-ui、redesign-piggy-screen、reorganize-status-screens など AI に画面を1枚ずつ作らせると、画面ごとに余白や色が微妙に違うものができあがります。 「余白はこの値」「色はこのトークンから選ぶ」を spec にしておくと、新しい画面を作るときも AI が既存のルールに合わせてくれます。 7. 「動くまで」ではなく「運用できるまで」をAIとやる アプリ本体以外にも、運用に必要なものを同じ流れで作っています。 Next.js の LP と、content/ を差分で取り込む管理画面(Google ログイン + TOTP) GitHub Actions での Flutter Web / LP / Supabase のデプロイ Firebase Analytics / サイト分析と、管理画面の KPI ページ 登録やログイン、LP のボタンのクリックを Slack に通知する Edge Function SEO(構造化データ・サイトマップ・Search Console) 個人開発では後回しにしがちな部分ですが、AI がいると「ついでにやっておく」ハードルがかなり下がります。 まとめ:AI開発で効いたこと 仕様書に「やらないこと」まで書く。AI の提案がぶれにくくなる いきなり実装させず、proposal / design / tasks を先に書かせる。人は日本語をレビューすればよくなる タスクの完了条件を「〇〇が通る」で書く。AI が自分で完了を判定できる コードから読み取れない決定だけを、1か所(config)にまとめて書く 変わりにくいドメインと、入れ替わるインフラを分ける。大きな方針転換にも耐えられる 質は文章の基準で、形式はスクリプトで守る 人のレビューの速さに合わせて、1つずつ進める AI が速く書けるようになった分、人の仕事は「何を作るか決めること」と「確かめること」に寄っていきました。 コードを書く時間が減った代わりに、仕様と基準を書く時間が増えた、というのが2週間やってみての実感です。 さいごに:マネランを遊んでみてください 🐷 マネランは、1回3〜5分で、社会人に必要なお金の知識が身につく無料の学習ゲームです。 「額面と手取りの違い」「住民税が2年目から増える理由」「NISA と iDeCo の使い分け」などを、クイズで少しずつ 続けるほど育つ貯金箱で、複利のしくみを体験 間違えた問題は「ミスモンスター」になって再登場。倒して図鑑を埋めよう 本物そっくりの偽メッセージを見抜く「詐欺バスター」で、詐欺への備えも 登録なしのゲストでもすぐに始められます。 この記事を読んで「AIで作るとこうなるのか」と思った方も、「給与明細、実はよく分かっていない…」という方も、ぜひ一度遊んでみてください。 👉 アプリ: maneran.web.app 👉 紹介ページ: maneran-lp.web.app 遊んでみた感想や、「こんな問題がほしい」「ここが分かりにくい」といった声も大歓迎です。コメントでお気軽にどうぞ!
The OpenSpec update I want first is the one that writes nothing I added a local note to a generated OpenSpec command, asked what an update would do, and checked the files afterward. The preview reported a replacement. Every file hash stayed the same. Then I ran the update. The local note disappeared. That is a useful distinction to see before your coding assistant starts following a different set of instructions. OpenSpec 1.15.0 adds update --dry-run, with a JSON form that lists planned file actions. It also ships a standalone CLI. The interesting part for an existing project is getting to inspect the replacement before accepting it. [1] !Executed OpenSpec fixture: add a local note, preview an update with unchanged file hashes, then apply the update and observe that the note is removed. Original diagram of the checked fixture below. It describes generated instruction files, not an AI coding session. The version number wasn’t the question An assistant integration has more moving parts than the executable. There are generated commands, skills, and the project’s own context. A current CLI does not tell you that every generated file matches its current template—or that you want it to. My fixture starts with a clean Claude integration and deliberately customizes .claude/commands/opsx/explore.md. It then checks three separate things: - Did the preview identify that command as an update? - Did previewing leave both the project and isolated configuration trees untouched? - Did applying the update actually replace the customization? The last check matters. A plan is useful evidence about an intended action; the resulting files establish what happened. 🔎 Here’s the output from OpenSpec 1.15.0: preview changed files: 0 custom command: update local note retained after update: False remaining planned changes: 0 The disappearing note is deliberate in this disposable example. In a real project, it could be the sentence you wanted your assistant to keep remembering. The update cannot decide whether that sentence was important to you. Run the same disposable check For a POSIX shell with Python 3.10 or newer, create a scratch directory and install the pinned standalone release into it. The installer selects a compatible release asset and checks its checksum. Other supported installation routes are in the project’s documentation. [2] mkdir openspec-preview-lab cd openspec-preview-lab curl -fsSL https://raw.githubusercontent.com/Fission-AI/OpenSpec/v1.15.0/scripts/binary/install.sh -o install.sh OPENSPEC_VERSION=v1.15.0 OPENSPEC_INSTALL_DIR="$PWD/.tools" sh install.sh .tools/openspec --version Save the following as preview_demo.py, then run python3 preview_demo.py from that directory. It uses a temporary project and separate configuration/data directories. The claude tool choice generates integration files; this script does not launch Claude or make a model request. 🧪 import hashlib import json import os import subprocess import tempfile from pathlib import Path binary = Path(os.environ.get("OPENSPEC_BIN", ".tools/openspec")).resolve() def manifest(root): return {str(p.relative_to(root)): hashlib.sha256(p.read_bytes()).hexdigest() for p in root.rglob("*") if p.is_file()} with tempfile.TemporaryDirectory() as directory: root = Path(directory) project = root / "project" project.mkdir() env = {**os.environ, "XDG_CONFIG_HOME": str(root / "config"), "XDG_DATA_HOME": str(root / "data"), "DO_NOT_TRACK": "1", "OPENSPEC_TELEMETRY": "0"} def run(*args): return subprocess.run([str(binary), *args, str(project)], env=env, check=True, capture_output=True, text=True).stdout run("init", "--tools", "claude", "--profile", "core", "--no-animation") command = project / ".claude/commands/opsx/explore.md" command.write_text(command.read_text() + "\nLOCAL_NOTE: review this customization.\n") before = manifest(root) plan = json.loads(run("update", "--dry-run", "--json")) assert manifest(root) == before edits = [c for c in plan["changes"] if c["path"] == ".claude/commands/opsx/explore.md"] assert len(edits) == 1 and edits[0]["action"] == "update" print("preview changed files:", len([p for p in before if manifest(root).get(p) != before[p]])) print("custom command:", edits[0]["action"]) run("update") assert "LOCAL_NOTE" not in command.read_text() print("local note retained after update:", "LOCAL_NOTE" in command.read_text()) again = json.loads(run("update", "--dry-run", "--json")) assert again["changes"] == [] print("remaining planned changes:", len(again["changes"])) The manifest includes relative file paths and content hashes. Comparing the complete dictionaries catches additions and deletions as well as changed contents. Merely checking modification times would be a weaker test: a file can be rewritten with identical bytes. The isolated configuration directory is intentional. The preview can include OpenSpec configuration actions alongside project instruction changes. I want the disposable check to include those effects without borrowing settings from another project. The source defines XDG_CONFIG_HOME as a supported override. [3] Read the action, then inspect the difference The JSON describes which files would be added, updated or deleted. That is not a semantic review of the new instructions. action: update cannot tell you whether a sentence became less precise, a local restriction disappeared, or a workflow now expects another artifact. ⚠️ My mistake would be treating a clean preview as permission to replace everything. “This command is generated” and “this command contains no useful local changes” are different facts. For a maintained project, I’d first save the current files in version control. I’d inspect the preview, apply the intended update, then read the actual diff before using the assistant integration. If a customization belongs in a project-owned instruction file, move it there deliberately and check that the relevant tool reads it. Avoid assuming every tool has the same override rules. ✅ This fixture checks one generated Claude command and the isolated trees around it. It establishes the preview’s behavior for that case. It does not establish preservation rules for every integration, validate the meaning of generated instructions, or prove that an agent will obey them. The useful addition is modest and practical: an update now has a readable “before” state. I’d rather discover the disappearing sentence there than after asking an assistant why it stopped doing something. References 1. OpenSpec 1.15.0 release: standalone install and update dry run. 2. OpenSpec installation documentation. 3. OpenSpec 1.15.0 configuration-directory implementation. Asset credit: original diagram of the executed disposable OpenSpec fixture. AI disclosure AI was used to draft the article.
OpenSpec's Oct 24 release adds an update dry-run: see which files would be added, changed or deleted without writing them. I appreciate software that shows the furniture plan before rearranging the room. github.com/Fission-AI/OpenSpec/releases/tag/v1.15…
OpenSpec - Spec-Driven Development for AI Coding Assistants OpenSpec is a spec-driven development framework with over 73,000 GitHub stars and 5,000 forks. Perfect for both solo and team projects, it helps you and your AI stay honest on a single repo. Learn more at openspec.dev. Link in first comment 👇 #OpenSpec #AI #CodingAssistants 🔗 Fission-AI/OpenSpec
SDD наоборот: не программируем по спекам, а получаем их на сдачу Недавно мне нужно было внести изменение в проект, где не было никакого SDD-фреймворка. Вообще никакого, Карл! Ни proposal, ни design, ни дельт спек, ни даже скромного tasks.md в уголке. Я морально приготовился к долгому онбордингу агента: сейчас он будет час ходить по коду, путаться в модулях и спрашивать, где тут вход. А модель просто разобралась в коде, нашла места будущего вмешательства, сделала изменение, и оно спокойно прошло человеческое ревью у кодовнера. Без единой спеки. «А что, так можно было?» После этого я посмотрел на свой рабочий проект с OpenSpec, на папку openspec/ с её двумя сотнями файлов, и задал себе резонный вопрос: зачем мы генерируем, храним и заносим под git кучу артефактов, которые современной модели не нужны? Кому мы пишем эти бумаги, если главный читатель прекрасно обходится без них? Из этого вопроса вырос SlimSpec, плагин для Claude Code. Он берёт из SDD то, что работает, и выкидывает остальное. На реальном проекте сопоставимое изменение обошлось ему в 29,7M токенов против 45,7M у OpenSpec, а в git не попало ни строчки процессных файлов. Дальше расскажу, откуда взялась идея, как устроен флоу, покажу цифры и то, чем пришлось заплатить. Спойлер: заплатить пришлось, бесплатных обедов не бывает даже в мире LLM. Зачем вообще был нужен SDD Ещё недавно модели были слабее, контекст маленьким, сабагентов не было. Работали так: в одной сессии составляешь подробный план, в следующей его реализуешь. Модель постоянно теряла контекст, как золотая рыбка, которая на третьем круге аквариума снова знакомится с замком. И память о проекте приходилось куда-то складывать, иначе каждая сессия начиналась с «привет, я новый джун, расскажите мне всё с начала». Spec-driven development закрывал ровно эти боли: маленький контекст, отсутствие сабагентов, нужда в подробном плане. Записал всё на бумажку, бумажку положил в репозиторий, следующая сессия бумажку прочитала. Надёжно, как швейцарские часы. Так он и стал стандартом. Тогда же появились два главных, на мой взгляд, фреймворка: OpenSpec и Superpowers. Я поработал с обоими, основным у меня стал OpenSpec. За что я их ценил: режим explore (в Superpowers он называется brainstorming), где дизайн складывается раньше плана. Это вообще лучшее, что случилось с AI-разработкой: сначала думаем, потом пишем код, а не наоборот; сам план и спецификации; у OpenSpec ещё и мерж спек: в живой спеке остаётся только важное. Superpowers этого лишён напрочь и просто копит design-файлы, как бабушка пакеты под раковиной. Выкинуть жалко, а найти нужный уже нельзя. В SDD-флоу, каким его видело сообщество, всё это ложилось идеально. Где OpenSpec начал тормозить В пет-проектах я долго сидел на OpenSpec с «китайскими» моделями и проблем не видел. Скорее наоборот: код стало легче писать и поддерживать, пропали семантические дубли (ну вы знаете, когда в проекте вдруг находятся три функции форматирования даты), агент чаще делал то, что нужно, и делал правильнее. На коммерческом проекте мы командой тоже выбрали OpenSpec, и поначалу я был в этом уверен на сто процентов. Через пару месяцев стало понятно, что флоу очень медленный. Особенно когда мы ушли от ручного ревью. Подписка корпоративная, лимиты жалеть незачем, мы шпарили в несколько окон терминала над разными фичами, а процесс всё равно тянулся, как очередь в МФЦ за справкой о том, что у тебя есть справка. Что тормозило: После proposal идут ещё четыре артефакта: design, tasks, дельты спек и прочее. Мы их практически не читали. Но они честно писались, коммитились и уезжали в архив. Без бумажки ты букашка, а с бумажкой… ну, тоже букашка, только с бумажкой. Любая правка в незаархивированном change выливается в ещё один change. Передумал по ходу? Будьте добры, заполните заявление по форме. Перед архивацией обязателен ребейз. И ещё надо попросить агента «ручками» проверить мерж спек, потому что кто-то другой мог залезть и «испортить» секцию, в которую вписывается MODIFIED-блок. Мой личный рекорд бюрократии выглядит так. Нужно было выпилить фичу: ненужный кусочек экрана. Задача на удаление, что может быть проще? Удалить код, удалить тесты, закрыть тикет. Итоговый дифф: Почти 5,5 тысячи строк ушло, и почти столько же пришло. Пришли, конечно, спеки: proposal о том, зачем удаляем, design о том, как удаляем, tasks о том, в каком порядке удаляем, и дельты REMOVED о том, что именно удалили. Чтобы выкинуть 5 тысяч строк, пришлось написать 5 тысяч строк. Это как сдать старый диван на свалку, но сначала заполнить на него техпаспорт, акт приёма-передачи и опись царапин. А потом случился тот самый проект без фреймворка. И пазл сложился. Основная сессия и есть дизайн Всю механику я давно отдаю сабагентам. Основная сессия у меня превратилась в разговор: брейнштормлю фичу с агентом, и тут же рождаются дизайн и план. Отступления от плана фиксируются там же, новых changes не нужно. Если доработка разрастается, агент сам предлагает вынести её за скоуп, в non-goals. Никаких заявлений, никаких форм. Сказал «давай иначе», и стало иначе. Выходит, источник знаний о фиче у меня уже есть, это сама сессия. Файлы нужны только на случай, если сессия потеряется или её пережуёт компакшн. Как запасной парашют: хорошо, что он есть, но прыгать с ним каждый день необязательно. Отсюда и «SDD наоборот»: не спека ведёт работу, а работа в конце оставляет после себя спеку. Артефакты изменения: OpenSpec против SlimSpec Вокруг этой идеи я и решил собрать свой фреймворк. Взять лучшее у предшественников и сделать легче, быстрее и дешевле. Классическое «я его слепила из того, что было», только с TDD. Как устроен SlimSpec Внутри только скиллы и описания агентов для Claude Code. Скриптов, хуков и CLI нет, ломаться там особо нечему. Ставится и запускается так: /plugin marketplace add yushman/slimspec /plugin install slimspec@slimspec /slimspec <идея> sourcecraft.dev Весь цикл на одной картинке: Флоу SlimSpec: explore → plan → apply → verify → ground Начинается всё с explore. Сабагент-сканер читает спеки модулей, потом код, и приносит короткую сводку: что тут есть, где что лежит, что может сломаться. Дальше основная сессия меня грилит: один вопрос на одно решение, независимые вопросы приходят пачкой. Ощущение как на собеседовании, только собеседуют твою же идею, и это полезно: половина «очевидных» решений на втором вопросе оказывается не такой уж очевидной. Итог ложится в explore.md: цель, non-goals, решения с отвергнутыми альтернативами, риски. Отдельных proposal и design нет, explore и есть спека изменения. К плану сессия сама не переходит, это решаю я. В plan планировщик раскладывает работу в tasks.md по волнам. Волна делится на дорожки (lanes) из связанных задач. Дорожки одной волны трогают непересекающиеся файлы, поэтому идут параллельно. Слона едят по частям, но если частей несколько и тарелки разные, их можно есть одновременно. У каждой задачи сразу записан первый падающий тест. Волны и дорожки в tasks.md apply короче всех: на дорожку по implementer’у, он идёт по задачам по порядку и на каждую приносит red и green. После волны основная сессия гоняет весь набор тестов, чтобы две параллельные дорожки не подрались где-нибудь на стыке. С verify интереснее. Ревьюер сверяет результат с планом и дизайном и смотрит, что red упал по делу, а не из-за опечатки или забытого импорта. Тест, который падает с ModuleNotFoundError, это не red, это просто красный. Код-ревью он отдаёт встроенному /code-review. Баги в коде автоматически уходят обратно в apply. Вопросы к дизайну приходят ко мне через refine: он правит explore.md и возвращает в apply только инвалидированные задачи. Галя, у нас отмена, но только трёх позиций, остальные пробиваем. Если два автоматических круга исправлений не помогли, сессия зовёт меня. Про ground ниже отдельно, там самое главное. Остановок две: после explore и после plan. На каждой сессия показывает подробный разбор. После explore это дизайн с диаграммами «было/стало» и ссылками на path:line, после plan все волны, дорожки и тест на каждую задачу. Остальное едет само и дёргает меня только вопросами. Можно спокойно пойти за кофе. Можно даже за вторым. Сабагенты не разговаривают с пользователем Решения принимает основная сессия. Сабагенты работают по принципу «каждый сверчок знай свой шесток»: сделал свою часть и отчитался. Отчёт короткий и структурированный, без логов и диффов: status: DONE | BLOCKED | FAILED task: T3 files: [src/auth/token.ts, src/auth/token.test.ts] decisions: ["used existing clock abstraction"] deviations: ["renamed validate → verifyToken"] tdd: red: "token.test.ts: rejects expired token — FAIL (expected 401, got 200)" green: "12 passed" questions: [] sourcecraft.dev Упёрся в открытый вопрос: останавливается со статусом BLOCKED. Самостоятельно ничего не додумывает и «как-нибудь сам» не решает. Основная сессия спрашивает меня и перезапускает агента с ответом. Контекст основной сессии остаётся чистым, без простыней тестовых логов, но в нём лежит каждое решение и каждый итог. Основная сессия и сабагенты TDD и ревью вшиты во флоу По-моему, TDD и код-ревью уже стали стандартом, так пусть лучше живут во фреймворке, чем в чьей-то дисциплине. Дисциплина, как известно, заканчивается в пятницу вечером. TDD проверяется не хуком, а по свидетельствам: задачу без red-прогона verify не примет. Ты не пройдёшь! (с) Гэндальф, ревьюер на полставки. Где TDD неприменим (конфиг, стили, миграции), задача помечается test: none — <причина> с альтернативной проверкой, и все такие исключения видны на гейте плана. Спрятать «ой, тут тесты не нужны» в середину списка не получится. Два временных файла Изменение живёт в .slimspec/changes/<slug>/, там лежат explore.md и tasks.md. Папку SlimSpec сам добавляет в .gitignore, а после ground удаляет. Отряд не заметил потери бойца, и правильно сделал: всё полезное из бойца к этому моменту уже переехало в спеки. Историю хранят коммиты и обновлённые спеки. Потерялась сессия? /slimspec <slug> продолжит с того места, где остановились. Grounding: единственное, что осталось от SDD Последний этап, ground, наверное, единственное, что роднит SlimSpec с классическим SDD. Из изменения дистиллируются долговременные знания: поведение, инварианты, контракты, решения. План и процесс выбрасываются. Кому через полгода интересно, что задача T3 шла во второй волне? Правильно, никому. Дальше это вливается в спеку модуля, и здесь главное отличие от OpenSpec. Мерж идёт не по ADDED/MODIFIED/REMOVED-блокам. Его делает агент, которому понятны причины, структура и дизайн изменения. Противоречащее утверждение он переписывает, а не дописывает рядом. Иначе спека быстро превращается в «было так, но потом стало вот так, хотя смотри пункт 7». Потом агент проверяет, что обновлённая спека покрывает цель изменения и не спорит с принятыми решениями. Grounding: дистилляция и слияние в CLAUDE.md модуля Результат ложится во вложенный CLAUDE.md нужного модуля. Claude Code сам подгружает такие файлы, когда работает в этой директории, так что спека попадает в контекст без лишних движений и ровно там, где нужна. Одна спека на модуль вместо россыпи файлов по capability. Не надо помнить, какую спеку подсунуть агенту: он зашёл в модуль, и спека уже там. Цифры Хватит теории, давайте мерить. На SlimSpec я перевёл два своих проекта. Замеры делал на одном из них, looqlog. Это просмотрщик логов на Rust с веб-интерфейсом, раньше он жил на OpenSpec и переехал командой /slimspec:migrate-openspec. Миграция У нас было 23 файла спек, 23 изменения в архиве, 200 файлов в openspec/ и 733 килобайта истории. Не то чтобы всё это было нужно агенту, но раз уж начал собирать артефакты, становится трудно остановиться. OpenSpec SlimSpec Спеки поведения 23 файла, 2 941 строка, ~155 КБ 3 файла, 484 строки, ~34 КБ Архив изменений 23 изменения, 12 394 строки, ~733 КБ 0 Корневой CLAUDE.md 130 строк 121 строка Файлов в openspec/ 200 0 Миграция looqlog: OpenSpec против SlimSpec Сценарии WHEN/THEN влились в требования, которые они и описывали. Пустые разделы Purpose и шаблонные SHALL ушли (SHALL, SHALL NOT, SHALL ALWAYS… спека звучала как устав караульной службы). Агент читает только спеку модуля, в котором работает: правка в web/ подтягивает ~11 КБ, а не капабилити-файлы со всего дерева. Через четыре изменения на SlimSpec спеки модулей подросли до 4 файлов и 641 строки. Это всё ещё на 78% меньше, чем было у OpenSpec. Спеки растут, но растут как надо: вместе с кодом, а не вместе с бюрократией. Сколько стоит одно изменение Считал по транскриптам Claude Code. Токены здесь означают весь вход, который обработала модель (input + чтение кэша + запись в кэш), основная сессия и сабагенты вместе. Самая близкая по размеру пара: OpenSpec (logcat-padded-tags) SlimSpec full (iana-tz-hash) Изменено кода 409 строк, 4 файла, 1 модуль 435 строк, 15 файлов, 3 модуля Обработано токенов 45,7M 29,7M (−35%) Токенов на строку кода ~110k ~68k (−38%) Ревью нет 2 раунда verify на глубине high, один реальный блокер исправлен Закоммичено процессных файлов ~530 строк 0 Время с гейтами 91 мин 56 мин И это при том, что SlimSpec успел больше: 5 вопросов по решениям, 3 гейта, 9 задач в 3 волнах, ground в 4 спеки, ADR и оба README. Блокер, найденный ревьюером, был паникой на крайних датах. Та самая ошибка, которая в проде вылезает ровно 31 декабря в 23:59. В прогоне OpenSpec ревью не было вовсе. Стоимость изменения в токенах На мелких изменениях то же самое. Два изменения на OpenSpec обработали 31,5M и 45,7M токенов, два на SlimSpec (fast и medium) 6,8M и 12,5M. Один implementer в OpenSpec в одиночку съедал 13–16M токенов, сабагент SlimSpec 0–1M: каждому достаётся одна узкая дорожка, и ему не нужно читать весь мир, чтобы поменять одну функцию. Теперь оговорки, их лучше назвать самому, пока это не сделали в комментариях. n = 1–2 на подход, проект один. Статистики тут как в анекдоте про среднюю температуру по больнице. Мелкие изменения на SlimSpec были в 5–10 раз меньше по коду, так что часть разницы объясняется просто размером. Часть агентов SlimSpec работала на Sonnet или Haiku. А основная сессия full-прогона тащила посторонний контекст из более ранней работы, и это, наоборот, завышает её счёт. Так что цифры не бенчмарк, а наблюдение. Но наблюдение довольно громкое. Что не взлетело по дороге Гладко было на бумаге. Кое-что я сначала сделал иначе и потом переделывал. Implementer на каждую задачу. Выглядело красиво: свежий агент, узкий контекст, чистота и порядок. На деле каждый холодный старт заново читал explore.md, спеки и код. Сколько задач, столько раз «здравствуйте, а что у вас тут за проект?». Теперь один implementer ведёт дорожку из связанных задач. Worktree для изоляции в режиме full. Не взлетело, потому что worktree сабагента ответвляется от закоммиченного состояния и не видит незакоммиченных результатов прошлых волн. Вторая волна честно строила дом без первого этажа. Пришлось бы коммитить каждую волну. Оставил параллелизм по непересекающимся файлам в одном рабочем дереве. Хотел хук, который не даёт править код без падающего теста. Звучит строго и надёжно. Но промпт-хук не может проверить, что red-прогон действительно был, а хуки плагина включены всегда, независимо от режима. Охранник, который не умеет проверять пропуска, но стоит у каждой двери. Проверка переехала в verify. С настройкой вышла смешная история: сначала написал bash-визард. С менюшками, с вопросами, всё как у людей. Потом выяснилось, что скилл не умеет вести интерактивный скрипт, а ! в сессии работает без TTY. Визард получился красивый, но запустить его было нельзя. Сейчас /slimspec:init просто задаёт вопросы прямо в сессии. И мелочь, которая раздражала каждый день: в explore вопросы шли строго по одному. Ждёшь круг на каждое решение, даже когда все вопросы известны заранее. Ощущение как в техподдержке: «ваш вопрос очень важен для нас, оставайтесь на линии». Теперь независимые идут пачкой, до четырёх за раз. Чем пришлось заплатить Ложки нашлись, но осадочек остался. Вот что ушло вместе с лишними артефактами: Сценариев как готового списка тест-кейсов больше нет. Обоснования отдельных изменений частично пропали. Что-то осталось в ADR, остальное только в git-истории. Если вы любите археологию по git log, вам понравится. Самая большая спека модуля (~14 КБ) грузится целиком при любой работе в этом модуле. Работает только с Claude Code. OpenSpec поддерживает 30+ AI-инструментов, Superpowers тоже работает со многими агентами и умеет кучу всего помимо спек: отладку, worktree, ревью. SlimSpec закрывает только spec-driven цикл и не притворяется швейцарским ножом. Настройка под проект Конфиг необязателен, у каждого ключа есть дефолт. Не хотите ничего настраивать? Не настраивайте, всё заведётся и так. /slimspec:init спросит всё в сессии и запишет .slimspec/config.yaml: mode: medium # fast | medium | full spec: format: claude-md # claude-md | readme | central | native | none unit: auto # auto (по билд-файлам) | glob директорий, напр. "src/*/" adr: false # дополнительно вести решения в docs/adr/NNNN-*.md test: auto # или явная команда commit: none # none | lane | wave apply: agents: 3 # максимум параллельных implementer review: depth: auto # auto (по режиму) | low | medium | high models: {} # модели по ролям: scanner, planner, implementer, reviewer, grounder sourcecraft.dev Пара слов о том, что тут не очевидно. mode задаёт вес цикла. В fast explore и plan живут в одном файле, вопросов не больше трёх, implementer один, ревью на low. Это для «поменять текст кнопки и не сойти с ума». medium добавляет сканер, грилинг, планировщик и параллельные дорожки, ревью на medium. full сверху ставит явный гейт на explore.md и ревью на high, для изменений, после которых хочется спать спокойно. Можно вообще не выбирать: после скана /slimspec сам предложит режим по размеру изменения. spec.format решает, где живут спеки. По умолчанию это вложенные CLAUDE.md. Можно README.md рядом с кодом, общую папку specs/ для фич поперёк модулей, нативные доки языка (Go doc.go, Rust //!, Python docstring, KDoc) или none, тогда ground пропускается. Для тех, кто живёт по принципу «код и есть документация». spec.unit говорит, что считать модулем; auto находит границы по package.json, go.mod, Cargo.toml, build.gradle(.kts), pyproject.toml. commit включает коммит после каждой дорожки или волны. Коммитит только основная сессия, агенты никогда. Пушить SlimSpec не умеет в принципе, и это фича: никаких сюрпризов в main в три часа ночи. models раздаёт модели по ролям. По умолчанию сканер и implementer на Sonnet, а планировщик, ревьюер и grounder на Opus. Думать дорого, делать дешевле, вот и вся экономика. Если проект уже сидит на OpenSpec или Superpowers, есть /slimspec:migrate-openspec и /slimspec:migrate-superpowers. Переносятся только спеки: каждая привязывается к модулям, сжимается и сверяется с кодом. Где код расходится со спекой, решаете вы, потому что иногда врёт спека, а иногда код, и угадывать тут нельзя. Старые файлы удаляются только после вашего подтверждения. Вместо вывода Сильным моделям не нужны тяжёлые спеки. Им достаточно подсказать, что делать и где искать, остальное они восстановят из кода быстрее, чем дочитают четыре артефакта. Токены, которые уходят на proposal, который никто не откроет, лучше потратить на следующую фичу. А ещё лучше на новый проект. Миллион токенов туда, миллион сюда, а в итоге набегает на ещё один пет-проект, который давно лежит в списке «когда-нибудь». Если вы тоже упирались в медленный SDD-флоу, попробуйте SlimSpec на одном изменении и сравните со своим текущим процессом. Особенно интересно, как он поведёт себя в команде и на проектах крупнее моих. Пишите в комментариях или в issues, ругать тоже можно, только с цифрами. SlimSpec на GitHub · Сайт
spec 駆動開発のツールはまだマスター設計を考えていない:機能ごとの設計書が作った端から枯れていく AI に実装させる前に、機能ごとの設計ディレクトリ(要件・設計・タスク)を repo に置く。spec-kit や Kiro が広めたこの形は、2026 年 10 月時点でほぼ定番になった。 ところが、この形には「今のシステム全体の設計はどこにあるか」に答える場所が無い。設計書は機能ごと、変更ごとに作られ、merge されるたびに増えていく。それらを畳み込んだマスター設計、つまり「今の仕様はこれ」と言える 1 つの文書を、spec-kit も Kiro も持たない。AI は次の作業で、溜まった設計ディレクトリのどれかを今の仕様として読む。 知りたいこと 結論 根拠 なぜマスターが要るのか 機能ごとの設計書は差分の説明でしかない。差分を積んでも今の仕様にはならない 構造からの説明 今のツールはマスターを持っているか spec-kit と Kiro は持たない。持つのは OpenSpec だけで、それも変更提案を通らないコード変更はマスターに戻らない 公式ドキュメント、spec-kit の issue #620・#4940 どの repo に置くか どのツールも、既定では設計書をコードと同じ repo に置く。機密と読み手の違いを考えると、設計は専用の repo に分ける判断になる 構造からの説明、OpenSpec の Stores 自分たちで持つには 設計 repo に提案とマスターを置き、コードの PR から ID で参照させる 設計の提案 2026 年 10 月時点の主なツールを並べると、次のとおりである。 ツール 機能ごとの設計書 マスター設計 コードの変更がマスターに戻るか 設計を別の repo に置くには spec-kit specs/NNN-name/ 無い。維持の方式は「チームの選択」 戻す core コマンドは not planned プロジェクトはディレクトリ単位。別 repo の間は版付きの成果物か同期したコピーで、と案内するだけ Kiro spec ごとに requirements・design・tasks 無い。steering は前提の説明 手順なし multi-root workspace で、別フォルダの .kiro/ の spec も一覧に並ぶ OpenSpec openspec/changes/<名前>/ openspec/specs/ 変更提案を通ったものだけ Stores(ベータ)で設計専用の repo を持てる。同期はツールの外 機能ごとの設計書は「その時点の差分の説明」 機能ごとの設計ディレクトリに書かれているのは、「今の状態から、この機能でこう変える」という差分の説明である。merge した時点で、その差分はコードに入り、役目を終える。 差分を何本積んでも、今の仕様にはならない。たとえば、001 でメールとパスワードのログインを作り、9 か月後の 009 で二段階認証を足したとする。今のログインの仕様を知るには、001 と 009 を両方読んで頭の中で合成しなければならない。その間にレビューの手直しや障害対応でコードだけ変わっていれば、どちらの設計書にも書かれていない。 人間なら、古い設計書を「経緯の記録」として読み流せる。AI はそうはいかない。repo に specs/001-login/spec.md があれば、それを今の仕様として読み、その前提でコードを書く。 設計書を artifact や Wiki ではなく repo に置けば、「コードと同じ PR で直せる」「履歴が残る」「AI がファイルとして読める」は手に入る。ただ、機能ごとの設計書が溜まるだけなら、AI が古い設計を正として読む事故は、置き場所を変える前と同じ形で起きる。要るのは置き場所ではなく、マスターである。 spec-kit:マスターは「チームの選択」 spec-kit の成果物は、機能ごとの specs/NNN-name/(spec.md、plan.md、tasks.md など)と、全体の原則を書く constitution.md である。constitution はテストの方針や設計原則を書く場所で、システムが今どう振る舞うかを書く場所ではない。 全体の今の仕様を持ちたい、という声は早くから出ている。2025 年 9 月に立った issue #620 は、まさに先の 001 と 009 の例を挙げて「仕様を時間とともに統合する推奨のやり方はあるか」と尋ねている。2026 年 10 月時点でも open のまま、「全体の今の定義を 1 か所で持ちたい」というコメントが続いている。 公式ドキュメントの答えは、Spec Persistence Models にある。配信後の設計書の扱いを flow-forward(完了した設計書は履歴として残し、変更は新しいディレクトリで行う)、living spec(機能の spec.md を契約として更新し続ける)、flow-back(実装で得た発見を設計書に戻す)の 3 つに分け、こう書いている。 None is the default, and none is required by Spec Kit. living spec でも、更新し続けるのは機能ごとの spec.md である。機能をまたいで今の仕様を 1 つにまとめる場所は、どの方式にも無い。 2026 年 10 月 13 日には、実装との食い違いのうち「コードが正しい」ものを spec と plan に書き戻す core コマンドの提案(#4940)が出た。これは同じ日に not planned で閉じられた。メンテナの説明は「配信と、配信後の維持は別物である。維持の方式はチームが選ぶもので、core がコマンドを用意する約束はしない」というものだった。 一方で、設計思想を書いた spec-driven.md にはこうある。 Specifications stay in sync with code because they generate it spec がコードを生成するので同期は保たれる、という主張である。これは機能ごとの spec と、そこから生成したコードの間の話で、マスターの話ではない。「同期する」という言葉が、全体の今の仕様はどこにあるかという問いを見えなくしている。 コミュニティには、merge 後に機能の設計を中央の .specify/memory/spec.md に畳み込む archive 拡張がある。マスターを欲しがる人が自作している、というのが 2026 年 10 月時点の状態である。 Kiro:steering は設計ではない Kiro の設計書も spec ごとに作られる。1 つの spec が requirements.md(または bugfix.md)、design.md、tasks.md を持つ。 全体の文脈として、Kiro には .kiro/steering/ がある。標準の 3 ファイルは次のとおり。 product.md:製品の目的、対象ユーザー、主な機能、事業の目標 tech.md:フレームワーク、ライブラリ、開発ツール、技術的な制約 structure.md:ファイル構成、命名規則、import の書き方、アーキテクチャ上の判断 どれも、AI にプロジェクトの前提を伝えるためのものである。「ログインは今どう振る舞うか」を書く場所ではない。 発表記事(2025 年 7 月 14 日)は「Kiro's specs stay synced with your evolving codebase.」と書いている。公式ドキュメントで同期の手段として挙がっている Sync Files は、設計を直したあとにタスクを作り直すことと、実装済みのタスクに完了の印を付けることをする。どちらも 1 つの spec の中の話で、spec をまたいで今の仕様をまとめる機能ではない。 唯一:OpenSpec はマスターを持っている OpenSpec は、マスターを最初から設計に入れている。spec-kit の #620 にも「それがまさに OpenSpec の売りだ」というコメントが付いている。 openspec/specs/ を source of truth(今の振る舞い)とする。 変更は openspec/changes/<名前>/ に提案として置く。spec には差分(ADDED / MODIFIED / REMOVED)だけを書く。 /opsx:archive で差分をマスターに merge し、提案は changes/archive/ に凍結する。 「変更提案は凍結し、今の仕様は 1 つだけ更新し続ける」という分け方で、RFC や ADR を運用してきたプロセスと同じ構造である。 ただし、マスターが更新されるのは、変更提案を通ったときだけである。手でコードを直したときは「archive の前に揃える」と FAQ にある。食い違いを見つける /opsx:verify は任意で、Verify won't block archive と明記されている。verify の対象は 1 つの change で、change を作らずに直したコード(レビュー後の手直し、障害対応、リファクタリング)を、マスターと突き合わせる仕組みは無い。 設計の repo をコードの repo から分ける マスターをどこに置くか。spec-kit は specs/、Kiro は .kiro/、OpenSpec は openspec/ と、どのツールも、既定では設計書をコードと同じ repo に置く。同じ PR でコードと設計を直せるので、ずれを防ぐには一番強い置き方に見える。 しかし、設計をコードの repo に置くと決める前に、2 つの点で設計 repo を分ける判断が要る。 機密:読める範囲は repo 単位でしか切れない 設計の背景には、コードの repo に入れられないものが混ざる。 特定の顧客の要望、契約条件、障害の相手先 料金や取引の事情、まだ公表していない計画 個人情報を含む問い合わせの中身 GitHub の読み取り権限は repo 単位である。「この repo のコードは読めるが、specs/ の下は読めない」という設定はできない。コードの repo に設計を置いた時点で、その repo を読める全員、つまり開発者全員、外部の協力者、CI、AI エージェントが背景まで読む。エージェントは読んだものを、コード、コメント、コミットメッセージ、PR 本文に書き出しうる。 背景を書かせないと、設計書は「AI は issue の背景を知らない」という元の問題に戻る。背景を書かせて、読める範囲を絞りたいなら、設計を別の repo に置くしかない。 読み手:設計を承認する人はコードの repo にいない 設計を「これで合っている」と承認するのは、PdM や顧客の窓口であることが多い。この人たちは、コードの repo に入る必要がない。設計がコードの repo にあると、承認のためだけにコードの読み取り権限を渡すことになる。 spec-kit は、この読み手の違いには気づいている。/speckit.specify の指示には、spec.md は「何を・なぜ」に絞り、開発者ではなく事業側の関係者に向けて書く、とある。ただ、その spec.md はコードの repo の中にある。事業側の関係者が読むには、コードの repo の権限が要る。 画面も同じである。人が意図を確かめるのは、文章より画面の画像である。merge 時点の画面を画像で固定して設計に添えると、コードの repo の履歴に画像が積み上がっていく。設計の repo なら、そこは気にしなくてよい。 分けると何を失うか 分けると、「同じ PR でコードと設計を直せる」が消える。2 つの repo は別々に merge されるので、何もしなければ、設計を artifact や Wiki に置いていたときと同じ形でずれる。分けるなら、このずれを塞ぐ仕組みを先に用意する必要がある。 Kiro は multi-root workspace で、複数のフォルダの .kiro/ にある spec を 1 つの一覧に並べて読める。設計用のフォルダを別に開いておく使い方はできるが、両者をつなぐ仕組みは無い。設計専用の repo を正面から扱っているのは、OpenSpec の Stores(2026 年 10 月時点でベータ)だけである。ドキュメントの説明は「planning in its own repo」で、複数の repo にまたがる機能や、要件を持つチームと使うチームが違う場合を動機に挙げている。機密や承認者の範囲は動機に入っていない。そして、2 つの repo の同期はツールの仕事ではないと明記している。 OpenSpec never clones, syncs, or pushes anything on its own. マスターから設計する 2026 年 10 月時点のツールがマスターも repo の分け方も考えていない以上、チームが先に決めるしかない。順番は、機能ごとの設計書の書式より先に、マスターをどの repo に置くかである。 1. 設計 repo を作り、変更提案とマスターをそこに置く。 issue ごとの提案(背景・設計・手順)と、今の仕様を書くマスターを、同じ設計 repo に置く。読み取り権限は、背景を読んでよい人に絞る。PdM や顧客の窓口は、この repo だけに入れる。画面は merge 時点の画像で固定し、ここに置く。 2. 提案は merge の時点でマスターに反映し、凍結する。 AI への指示(CLAUDE.md や AGENTS.md)に「今の仕様はマスターを読む。提案は経緯として読む」と書けば、エージェントの読み方が一意に決まる。マスターの記述が変わらない小さい修正には、提案を要求しない。 3. コードの PR から、設計 repo を ID で参照させる。 同じ PR で直せない分は、CI で塞ぐ。コードの repo の PR には、次のどちらかを求める。 設計 repo の提案の ID を書く。CI は、その提案が承認済みかを確かめる。 PR 本文で「仕様は変わらない」と宣言する。 逆向きも見る。設計 repo の提案を凍結するときは、対応するコードの PR が merge 済みかを確かめる。提案を通らないコード変更がマスターに戻らない問題は、ツールの中だけで閉じている OpenSpec でも残っている。repo を分けるなら、この往復の検査が無いと必ずずれる。 4. AI には作業ごとに必要な分だけ渡す。 コードの repo で動くエージェントに、設計 repo 全体を読ませない。その作業の提案と、マスターの該当箇所だけを渡す。背景のうちコードに書き出してはいけないものは、提案の中で分けておく。 spec 駆動のツールは、1 つの機能を書き始めるまでを速くした。機能が積み上がったあとに「今の仕様はどこか」に答えること、そして「設計を誰に読ませるか」を決めることは、まだツールの仕事になっていない。設計を repo で持つと決めたら、どの repo に置くかと、コードの repo とをつなぐ検査も一緒に決める必要がある。 参考 github/spec-kit: spec-driven.md github/spec-kit: Spec Persistence Models github/spec-kit: Evolving Specs in Existing Projects github/spec-kit: Using Spec Kit in a Monorepo github/spec-kit #620: How to keep specs consistent and up-to-date with spec-kit? github/spec-kit #4940: Core flow-back step for drift where the code is ahead of the spec github/spec-kit Discussion #1804: How do you keep your spec files canonical? Introducing Kiro Kiro: Steering Kiro: Specs best practices Kiro: Multi-root workspaces OpenSpec: Concepts OpenSpec: FAQ OpenSpec: Stores: Plan in Its Own Repo