claude-project-flow
releasev3.0.2A Claude Code plugin that carries a project from a rough idea to shipped code through six approval-gated phases
README Snapshot
claude-project-flow
A Claude Code plugin that carries a project from "I have a rough idea" to working code through six approval-gated phases — and refuses to write a line of application code until the first five are done.
The problem it solves is the pair of failure modes an AI assistant falls into on a new project: it starts building on a guess, or it asks questions forever. This fixes both with a bounded checklist, evidence from real research instead of recall, and a set of documents that hold the memory so the conversation does not have to.
Install
/plugin marketplace add voyvodka/claude-plugins
/plugin install project-flow@voyvodka
The plugin is listed in a small catalog marketplace
rather than being one itself, so a single registration covers every plugin from the same author and
/plugin marketplace update voyvodka refreshes all of them at once.
The owner/repo shorthand clones over SSH. Without an SSH key on the machine, use the HTTPS URL
instead — it needs no credentials for a public repository:
/plugin marketplace add https://github.com/voyvodka/claude-plugins.git
Then, in any project folder:
/project # start, or resume wherever the folder left off
/project a tool that does X # start with a rough idea
Always the same command. It reads docs/product/00-state.md to work out whether this is a new
project, a resumption, or a request to advance — an empty folder, a half-finished plan, and an
existing codebase all route correctly.
The six phases
| Phase | Does | Writes code |
|---|---|---|
| 0 · Detect | Classifies the folder, reports where things stand | No |
| 1 · Discover | Bounded question rounds against a fixed checklist | No |
| 2 · Research | Subagent fan-out: market, tech, dev environment | No |
| 3 · Decide | Findings become owned decisions and an MVP scope | No |
| 4 · Scaffold | CLAUDE.md, AGENTS.md, right-sized AI tooling |
No |
| 5 · Build | Implements the roadmap in approved increments | Yes |
Every boundary is a gate the user opens. A phase can be skipped when it does not apply — but never silently: it says what it is skipping, why, and writes that into the state file.
What it leaves behind
<project>/
├── CLAUDE.md main context source
├── AGENTS.md pointer for non-Claude tools
├── docs/
│ ├── product/ 00-state · 01-brief · 02-decisions · 03-mvp · 04-roadmap
│ └── research/ market · tech · devenv
└── .claude/
├── agents/ project-specific subagents — few, or none
└── skills/ only for genuinely repeated work
All of it is meant to be committed. Someone who clones the repo — using Claude Code, opencode, or
anything else — reads CLAUDE.md and docs/product/00-state.md and continues from the same line
of thought. That handover is the point of the whole thing.
The ideas it is built on
- No application code before Phase 5 is approved. If you ask for code earlier, it names what is still unknown and offers to fast-track the remaining phases rather than silently starting.
- Documents are the memory, the conversation is not. Anything confirmed is written down before moving on, as if the chat will be lost mid-sentence.
- Ask, but bounded. A fixed checklist with a round limit. Remaining unknowns become marked assumptions, raised again at the moment code depends on one — never more rounds of questions.
- Research runs in subagents. Each branch digs deep in its own context, writes straight to its own file, and returns ten lines. That is what keeps one long chat viable.
- Right-size everything. A weekend script gets a weekend-sized plan, two doc files and zero custom subagents. Preventing over-engineering is the reason this exists.
- Never invent a fact. Market numbers, competitor names, library versions and pricing come from research with a source, or they are written down as assumptions. Never from memory presented as fact.
- Decisions are updated in place. Git holds the history; the file always reads as current truth. A reversal is a sweep through everything that encoded the old choice, not a paragraph added below it.
The developer profile
plugins/project-flow/skills/project-flow/profile/ is the part you are meant to edit. It records what
you already know and reach for by default, one file per stack, so a project reads only what it
touches.
With it filled in, Phase 2 stops asking "which stack?" and starts asking "is there a reason to deviate from the default here?" — faster, and a better question, because it forces a candidate to beat the default on something the project actually needs.
The files in this repository are one developer's answers, kept as a worked example rather than as advice. Replace them. A profile describing someone else is worse than an empty one, because it will be trusted.
Keeping your real profile out of git
profile/local/ is gitignored, and any file placed there is read instead of the file with the
same name one directory up:
profile/infrastructure.md committed — the template
profile/local/infrastructure.md ignored — the real one, read in preference
That is where hostnames, machine limits, git identity and repository paths belong. Two files
ship as templates for exactly this reason — infrastructure.md and local-environment.md — and
until one is filled in or overridden, the plugin treats its subject as genuinely open and asks
rather than assuming.
This requires running the plugin from a copy you own. A marketplace install is copied into a
versioned plugin cache, and that breaks the override in both directions: the clone it was built
from never contained local/, and a local/ you create inside the cache is deleted by the next
update. Nothing errors when it fails — the templates are read instead, and the tool proceeds
trusting answers that describe a different developer, which is exactly the outcome the profile
warns about.
Two ways to have a real profile:
# clone it, and point a skills directory at the plugin — discovered in place, no cache copy
git clone https://github.com/voyvodka/claude-project-flow.git
ln -s "$PWD/claude-project-flow/plugins/project-flow" ~/.claude/skills/project-flow
or install from the marketplace and edit the committed profile/ files directly, accepting that
an update overwrites them. If you do neither, treat every default in profile/ as someone else's
and expect Phase 1 to confirm each one with you.
It reviews itself
At every phase gate the tool asks whether anything went wrong because of how it is written, separates structural failures from circumstantial ones, and logs them. The bar for acting is evidence from a real project, not taste, and the preferred fix is to remove the cause rather than add a reminder. It proposes changes; it never applies them to itself without approval.
plugins/project-flow/skills/project-flow/feedback/observations.md is that ledger, and
plugins/project-flow/README.md records why each version changed — reasoning, not a changelog. Both
include the findings that were rejected, and one that shipped and had to be reverted, because
the reason a plausible rule was wrong is the only thing that stops it coming back.
Language
Conversation and everything under docs/ follow the user's language. CLAUDE.md, AGENTS.md,
.claude/**, all code and all commit messages are always English.
Repository layout
plugins/project-flow/ the plugin — see its own README for detail
Licence
MIT — see LICENSE.
Changelog
Changelog
All notable changes to the project plugin are documented here.
The format follows Keep a Changelog, and this project
adheres to Semantic Versioning.
The Status section of the plugin README carries the reasoning
behind each change — why the tool needed it. This file carries what changed. Releases before 2.7.0
are summarised from that section and from git history.
[Unreleased]
[3.0.2] - 2026-09-08
Fixed
- The research phase told the subagent to use Context7 and gave it no way to proceed without it.
phase-2-research.mdsaid "use Context7 (resolve-library-id, then query-docs) … Do not answer from memory", but this plugin declares no dependency on Context7 and nothing installs it. On a machine without it the branch had an instruction it could not follow and no stated alternative, against a rule that forbids answering from memory — so the only exit was the one the rule forbids.profile/code-style.mdalready said "Context7 or the registry", so the two files disagreed about whether the tool was required. The rule now leads with what is actually non-negotiable (never answer from memory), prefers a docs tool where the session has one, and names the registry commands to fall back to. The siblingweb-launcherskill reached the same shape from the same problem. self-improvement.mdsent the observation log into a directory the next update deletes. "Where the edit has to land" tells the reader to stop when${CLAUDE_PLUGIN_ROOT}is inside aplugins/cache/path, but the "Logging" section below it said, without qualification, to append tofeedback/observations.md— a file in that same cache. A reader arriving straight at Logging appended an observation that a marketplace update then wiped, silently, having counted it as recorded. The constraint is now restated where the writing actually happens.- Two release blocks in this changelog held the same fixes twice.
3.0.1and2.8.0each carried two### Fixedheadings, because separate pull requests each appended to[Unreleased]and the release stamped both without merging them.3.0.1's second block restated the first in different words;2.8.0's split thirteen genuine entries across two lists with a### Changedbetween them. Merged, with every unique entry kept.
Added
- CI checks the changelog's structure: no section heading twice inside one version block, only
Keep a Changelog section names, an
[Unreleased]section that the next change can land in, and one dated heading per version. The duplication above was found by reading the file weeks later, and it is mechanically detectable — so it is checked rather than trusted, which is the standard this plugin applies to every project it touches.
[3.0.1] - 2026-08-28
Fixed
phase-3-decide.mdtold the reader the decision record has four fields, while a paragraph further down — untouched by that edit — describesKabul edilen bedel/ accepted cost as mandatory, down to what to write when there is none. An agent following the explicit "four fields are what is fixed" instruction would drop it. The reference now describes all five, in both the Turkish block and the English label mapping, and says to write "—" when a decision genuinely costs nothing rather than dropping the line.- The plugin README's
Statussection went stale twice in one day: backfilled at 2.7.0, then three more releases shipped past it. The cause was keeping the same history in two files, so the cause is gone —CHANGELOG.mdis the record from 2.7.0 onward andStatusis explicitly frozen pre-2.7.0 history. This plugin tells every project it touches to write once and link; it now does. - The CI routing check aborted opaquely on the condition it exists to report:
grepexits 1 when it matches nothing, and underset -eo pipefailthat killed the step before the::error::annotation was printed. It now annotates and fails deliberately.
Changed
- The README's
Statussection is frozen as pre-2.7.0 history. It duplicated the changelog and went stale twice in one day, which is the failure this plugin warns about everywhere else. The authoritative record from 2.7.0 onward isCHANGELOG.md; the older entries stay because their reasoning predates the changelog and is still worth reading.
[3.0.0] - 2026-08-28
Changed
The plugin is renamed from
projecttoproject-flow. BREAKING for the install key: it is now/plugin install project-flow@voyvodka, andenabledPluginsentries move accordingly. The catalog carries arenamesentry so Claude Code v2.1.193+ rewrites existing settings automatically and reports the change; because the source is remote, expect oneplugin-cache-missand a single/plugin installto pick it up under the new name.projectwas a bare dictionary word standing in for a plugin about phased project delivery. It collides easily —cyberswat/claude-plugin-projectsalready occupies the same space on GitHub — and a generic install key is the one identifier a user cannot disambiguate at install time. The skill one directory down has been calledproject-flowsince the first release; the plugin now matches it.The repository name (
claude-project-flow) is unchanged, and the/projectcommand is unchanged — it still starts, resumes and advances a project exactly as before. What moved is the install key and the skill's namespaced id, which is nowproject-flow:project-flow.plugins/project/is nowplugins/project-flow/, so the plugin directory matches the plugin name.
Fixed
- The
.gitignorerule protectingprofile/local/was pinned toplugins/project/...and stopped matching the moment that directory was renamed. An ignore rule a rename can silently switch off is not an ignore rule; it is now**/profile/local/. CI also asserts that nothing underprofile/local/is tracked, so the protection is checked rather than assumed.
[2.8.0] - 2026-08-28
Fixed
The research phase could carry private infrastructure detail into a committed file. The Tech branch is told to paste
profile/infrastructure.mdinto the subagent prompt. On any real machine that resolves toprofile/local/infrastructure.md, which is gitignored precisely because it holds hostnames, provider and account names, port lists, domain portfolios and backup schedules. That branch writes intodocs/research/tech.md— a file this tool tells the user to commit, in a different repository from the one the profile describes. Nothing said "conclusions, not transcription", so it depended entirely on the subagent's judgement. It is now an explicit rule, modelled on the wording the committedinfrastructure.mdalready applies to itself.Phase 2 could not tell an interrupted branch from a finished one. Branches write straight to their final file, so a session that dies mid-fan-out leaves a file Phase 0 reads as complete. Launched branches are now recorded in
00-state.mdat dispatch and marked done as each returns — the rule Phase 5 already applies to increments.SKILL.mdstated an absolute thatself-improvement.mdcontradicts. "This tool never edits itself without the user's approval" sat next to two documented repair exceptions. The exceptions are now named where the promise is made."No application code before Phase 5" vs the Phase 3 spike. Phase 3 explicitly writes and runs throwaway code. The directive now says "no code that ships" and names the spike as the one bounded exception, so the reader is not choosing which of two rules to break.
"Two documents instead of five" was never defined. Phase 1 offers the compact shape; Phases 3-5 then name
02-decisions.mdand04-roadmap.mddirectly, leaving a model that took the offer with two conflicting instructions. The compact layout is now a table naming exactly which file absorbs which, recorded in00-state.md.Nothing asked before writing over an existing
CLAUDE.md,AGENTS.mdordocs/tree. Phase 4 now stops, says what the existing file covers and where it disagrees, and offers merge / replace / write-alongside.The
Aktif fazfield enumerated phases 0-5 while Phase 5's closing step writes "MVP complete" into it, and nothing distinguished a phase that is running from one that finished. It now carries a parenthesised status.phase-0-detect.md's "Reconstructing state" section did not say it runs after approval rather than before; the heading now does.Phase 1's "round limit" was not a limit.
SKILL.mdpromises questioning is bounded and that leftover unknowns become marked assumptions, butphase-1-discover.mdonly said to announce a fourth round — with no ceiling and no conversion rule, so a user whose answers keep opening new ground could be questioned indefinitely, which is the exact failure the directive exists to prevent. Four rounds is now a hard ceiling; what is still open converts to marked assumptions and Phase 2 researches it.The decision-record format hardcoded Turkish field labels.
phase-3-decide.mdshowedKarar/Neden/Elenenler/Bağlı olduğu varsayımas the literal block to fill in, whileSKILL.mdsays product documents follow the user's own language — so an English-language project got Turkish headings inside otherwise English documents. The four fields are what is fixed; the labels follow the document.code-style.mdtold the agent to append to agotchas.mdthat nothing creates. No phase scaffolds it and no template defines it, so the rule fired mid-implementation against a file that did not exist. It now says to create it on first use, with the three-layer structure already described a few lines below — deliberately not scaffolded up front, so a project that never hits a warning does not carry an empty ledger.Two
avoid.mdexclusions (Sentry, API versioning) carried no argument, while the file's own rule is that a candidate "has to beat the stated reason". With nothing stated there was nothing to beat. Both are now marked as unargued weak priors to be raised in Phase 1 rather than treated as settled.The rejected entry in
feedback/observations.mdwas missing two fields its own logging template requires.
[2.7.0] - 2026-08-28
Fixed
- The self-improvement loop could write into a directory that gets deleted.
references/self-improvement.mdwalks through proposing a change and then applying it toSKILL.mdor a phase reference, and allows two classes of repair without asking — but never said where the edit lands. On a marketplace install that is a versioned plugin cache, wiped on the next update, silently, after the user approved the change and watched it be written.profile/README.mdalready documented this failure forprofile/local/; it now covers the whole skill, with a check against${CLAUDE_PLUGIN_ROOT}before anything is applied. - Phase 5 wrote a file no layout tree listed. A project
README.mdis written at MVP close from one of the two README templates, but neitherSKILL.md's target layout nor the plugin README's "What it produces" named it — whilephase-0-detect.mdtreats a rootREADME.mdas a pre-existing signal. Both trees now list it and say when it appears. - The
Statussection had stopped at 2.4.0 whileplugin.jsonwas at 2.6.0, so the reasoning for two releases existed only in commit bodies. Backfilled. profile/code-style.mdstated "Documentation is Turkish" as an unconditional rule for every project, contradictingprofile/README.md(everything underprofile/is a default confirmed in Phase 1) andSKILL.md(docume
Releases
- v3.0.2Open on GitHub
Fixed
- The research phase told the subagent to use Context7 and gave it no way to proceed without it.
phase-2-research.mdsaid "use Context7 (resolve-library-id, then query-docs) … Do not answer from memory", but this plugin declares no dependency on Context7 and nothing installs it. On a machine without it the branch had an instruction it could not follow and no stated alternative, against a rule that forbids answering from memory — so the only exit was the one the rule forbids.profile/code-style.mdalready said "Context7 or the registry", so the two files disagreed about whether the tool was required. The rule now leads with what is actually non-negotiable (never answer from memory), prefers a docs tool where the session has one, and names the registry commands to fall back to. self-improvement.mdsent the observation log into a directory the next update deletes. "Where the edit has to land" tells the reader to stop when${CLAUDE_PLUGIN_ROOT}is inside aplugins/cache/path, but the "Logging" section below it said, without qualification, to append tofeedback/observations.md— a file in that same cache. A reader arriving straight at Logging appended an observation that a marketplace update then wiped, silently, having counted it as recorded. The constraint is now restated where the writing happens.- Two release blocks in the changelog held the same fixes twice.
3.0.1and2.8.0each carried two### Fixedheadings, because separate pull requests each appended to[Unreleased]and the release stamped both without merging them. Merged, with every unique entry kept.
Added
- CI checks the changelog's structure: no section heading twice inside one version block, only
Keep a Changelog section names, an
[Unreleased]section that the next change can land in, and one dated heading per version.
Full changelog: https://github.com/voyvodka/claude-project-flow/blob/main/CHANGELOG.md
- The research phase told the subagent to use Context7 and gave it no way to proceed without it.
- v3.0.1Open on GitHub
Follow-ups from a full re-audit. All three are defects introduced or left standing by 3.0.0's own changes.
Fixed
phase-3-decide.mdsaid the decision record has four fields while a paragraph further down describesKabul edilen bedel/ accepted cost as mandatory, down to what to write when there is none. An agent following the explicit instruction drops the field the same file calls required — and it is the one that stops the next reader reopening a settled decision. The template now carries all five.- The plugin README's
Statussection went stale twice in one day — backfilled at 2.7.0, then three releases shipped past it. Resetting it a third time would be the weakest possible fix, so the cause is gone:CHANGELOG.mdis the record from 2.7.0 onward, andStatusis explicitly frozen as pre-2.7.0 reasoning. - The CI routing check aborted opaquely on the condition it exists to report.
grepexits 1 when it matches nothing, and underset -eo pipefailthat killed the step before the annotation printed. It always failed safe, but a gate that cannot say what it caught costs the next person the time it was meant to save.
- v3.0.0Open on GitHub
⚠️ Breaking: the install key changed
The plugin is renamed from
projecttoproject-flow:/plugin install project-flow@voyvodkaThe catalog carries a
renamesentry, so Claude Code v2.1.193+ rewritesenabledPluginsandpluginConfigsin your user, project and local settings automatically and tells you it did. Because the source is remote, expect oneplugin-cache-missand a single/plugin installto pick it up under the new name. On older Claude Code the old name reportsplugin-not-found— install the new one.Unchanged: the repository name, and the
/projectcommand. It still starts, resumes and advances a project exactly as before. What moved is the install key and the skill's namespaced id (project-flow:project-flow).Why
projectis a bare dictionary word standing in for a plugin about phased project delivery, and the plugin name is the install key — the one identifier you cannot disambiguate at install time.cyberswat/claude-plugin-projectsalready occupies the same space. The skill one directory down has been calledproject-flowsince the first release; the plugin now matches it, andplugins/project/becameplugins/project-flow/so the directory does too.Fixed
- The
.gitignorerule protectingprofile/local/was pinned to a literal path and stopped matching the moment the plugin directory was renamed — no error, no warning. It is now**/profile/local/, and CI asserts that nothing underprofile/local/is tracked, so the protection is checked rather than assumed. If you run this plugin from a clone with your ownprofile/local/, this is the release that makes that safe against future moves.
- The
- v2.8.0Open on GitHub
A privacy fix worth upgrading for, plus four contract mismatches.
Fixed — a gitignored file was feeding something that gets committed
phase-2-research.mdtells the Tech branch to pasteprofile/infrastructure.mdinto the subagent prompt. On any real machine that resolves toprofile/local/infrastructure.md— gitignored precisely because it holds hostnames, provider and account names, port lists, domain portfolios and backup schedules. That branch writes intodocs/research/tech.md, a file this tool tells you to commit, in a different repository from the one the profile describes. Nothing distinguished using that content for judgement from transcribing it. Now an explicit rule, worded after the constraint the committedinfrastructure.mdalready places on itself.Fixed — an interrupted research branch looked finished
Branches write straight to their final file, so a session that died mid-fan-out left a file Phase 0 read as complete. Launched branches are now recorded in
00-state.mdat dispatch and marked done as each returns.Fixed — the tool contradicting its own promises
SKILL.mdsaid "never edits itself without the user's approval" whileself-improvement.mddocuments two repair exceptions. The exceptions are now named where the promise is made.- "No application code before Phase 5" vs Phase 3's timeboxed throwaway spike. Now "no code that ships", with the spike named as the one exception.
- "Two documents instead of five" was offered without saying which two, while Phases 3-5 name files the compact shape does not have. There is now a table.
Fixed — Phase 4 overwrote existing context files silently
No merge, diff or approval step existed for a pre-existing
CLAUDE.md,AGENTS.mdordocs/tree. It now stops, says what is there and where it disagrees, and offers merge / replace / write-alongside.Also
The
Aktif fazfield enumerated phases 0-5 while Phase 5 writes "MVP complete" into it, and nothing marked a phase as running or interrupted. It now carries a parenthesised status. - v2.7.0Open on GitHub
Content fixes found by a full re-audit on 2026-08-28, plus the repository's first CI gate. First tagged release — earlier versions are summarised in CHANGELOG.md.
Fixed
- The self-improvement loop could write into a directory that gets deleted.
references/self-improvement.mdwalks through proposing a change and then applying it toSKILL.mdor a phase reference, and allows two classes of repair without asking — but never said where the edit lands. On a marketplace install that is a versioned plugin cache, wiped on the next update, silently, after you approved the change and watched it be written. There is now a check against${CLAUDE_PLUGIN_ROOT}before anything is applied. - Phase 5 wrote a file no layout tree listed. A project
README.mdis written at MVP close, but neitherSKILL.md's target layout nor the plugin README's "What it produces" named it — while Phase 0 treats a rootREADME.mdas a pre-existing signal. - The README's
Statussection had stopped at 2.4.0 while the manifest was at 2.6.0. Backfilled. profile/code-style.mdstated "Documentation is Turkish" as an unconditional rule for every project, against the profile's own default-not-a-rule framing and againstSKILL.md. Reworded. The English-for-code half is unchanged and still absolute.
Removed
- A stray
version: 0.1.0from theSKILL.mdfront matter, which Claude Code does not read and which contradicted the manifest.
Added
- CI that validates the manifest and asserts the phase routing, references and templates all resolve in both directions. This skill's failure mode is routing: a renamed reference breaks a phase at the moment that phase is needed, halfway through someone's project.
- Dependabot,
CHANGELOG.md, and$schemain the manifest.
- The self-improvement loop could write into a directory that gets deleted.