The Skill That Planned Its Own Release
The Skill That Planned Its Own Release
A planning plugin for Claude Code that won’t decide things for you, won’t build on a vague “go ahead”, and won’t call anything done without evidence. I used the old version to plan the new one. Along the way the plan invented a deadline, and two later sessions believed it.
The short version — if this box is all you read
- What it is: an MIT-licensed planning plugin for Claude Code. Ask it to plan something and it writes one plan file with a gate line per phase: intake, value, spec, review, plan, build, close.
- What it won’t do for you: set your priorities, decide whether the thing is worth building, start building on an earlier “go ahead”, or mark anything done because an agent said so.
- Install:
/plugin marketplace add johndelay/project-management-plugin, then/plugin install project-management@thedelay. Start it with “Use the project-management skill to plan …” - Why I rebuilt it: of the eight plans I’d made with the old version, none reached “done.”
- The twist: I pointed the old version at its own rebuild. Along the way, Claude wrote a one-week deadline into the plan that I never set, and later sessions treated it as mine. Now a decision exists only once the owner has answered.
- Does it help? With versus without, on nine test cases: it cleared the bar I set in advance on Sonnet and Opus. Haiku scored below it. Told “go ahead” with two questions still open, the last simulated stranger built nothing until they were answered.
- Honest limits: tested on Claude Code only, and the “strangers” were Claude playing engineers, not people. The gates don’t make an agent honest. They make it obvious when it isn’t.
$ /plugin install project-management@thedelay
Install it
You need Claude Code. That’s the whole list.
/plugin marketplace add johndelay/project-management-plugin
/plugin install project-management@thedelay
Start a new session, then, in any repo:
Use the project-management skill to plan <what you want>.
Plain planning words work too — “can you plan…”, “plan it and get it moving” — and a typo fix leaves it alone. A plain feature request doesn’t start it: “add CSV export” gets you an agent that just builds it. That’s on purpose; a wider trigger would push every small request through the whole flow. To use it for feature work in one repo, add this line to that repo’s CLAUDE.md (it’s the one I tested):
For a new feature, a new project, or a build that will span sessions, with no plan yet, use the
project-management skill. Not for routine ops, config changes, fixes or investigations, and not when
the user says to just do it.
On a small model, name it when you resume. On Haiku, a bare “go ahead” about an existing plan didn’t load the skill (0 of 3).
Optional: the full review skill. The plugin’s built-in review prompts are copied from my three-lens review skill. Install that skill too and you get review tiers, an audit log and a stopping rule. It isn’t a plugin yet: copy it in by hand before you start the session. The README says where from.
Not on Claude Code? The skill is a plain folder of Markdown, templates and a Python checker. Cursor, Codex and Copilot are untested. If you try one, open an issue.
What’s in the box
The plugin is one skill folder: Markdown, templates and a Python checker.
- The spine —
SKILL.md, the file the agent reads every time the skill fires. It holds the phases, the gate lines, the two owner checkpoints and the hard rules. It ships at 13,500 bytes and 165 lines — exactly on its budget. The size is deliberate: an agent reads it in full on every run, so it has a byte budget. The first draft landed under that budget in one go, because a table had already decided which requirement goes in the spine and which goes in a reference file, before any text was written. - Six reference files, each loaded only in the phase that needs it: review (the general prompt and the three lenses), verification, parallel work, owner communication, closing, and a short file for major multi-system work. That last one is labelled untested, and it is.
- Templates — the plan, a kickoff prompt for handing a stream to another session, an optional config file, and two ways to ask the owner questions: an HTML decisions page for tools that can publish one, and a plain Markdown decisions file for everything else.
- The checker —
pm-check, a read-only Python script: one file, 1,362 lines, standard library only. It checks a plan’s shape: are the seven gate lines there, in order, with valid states; does every Definition of Done item say how it’s observed; does a “no open decisions” claim sit next to an unresolved flag; did a template placeholder get left behind; did the build start before the go; is a plan labelled “small” actually small. It carries its own embedded control, so if the checker itself is broken, it exits 2 (“could not check”) instead of reporting a clean plan. Plans written before this version get information notes only, never errors — the older format was never going to pass a grammar it predates. Its test suite runs 85 cases and fails if the count is off. - The overlap guard — a
pm-check overlapsubcommand. Before a parallel stream is merged, it reads the real branch diffs and flags any file two streams both changed, or a stream that changed files outside the ones it owns. Planning who owns which files is the easy part. This checks what each stream actually changed. - A config file, if you want one. Without it, the skill says which defaults it is using: where plans go, how ids are numbered, which steps are yours. With one, you can set your plans folder, your id scheme, the actions you’ve pre-approved, and your branch rule.
What’s deliberately not in the box: the rest of my own setup — my notes search, my save routine, my coordination scripts, my hooks. For each one, the skill states the plain fallback it uses instead (grep instead of a search index, the plan’s gate lines instead of a status file, and so on). You get the method without my scaffolding.
$ cat plans/my-first-plan.md
Your first plan
Pick something real and smallish in a repo you know, and ask it to plan. The plan has seven phases and two points where it stops for you; here they are as nine steps.
One line: what it has and what it’s missing, with the fallback for each. Then the defaults it’s using, and git fetch on every repo it will touch — a file on disk says nothing about the remote.
Two asks and a “don’t touch billing” in one message? You get a numbered readback, each ask tagged build now / defer / needs decision, and “don’t touch billing” lands under Constraints & Gotchas instead of dying in the scrollback.
Does it already exist (it searches your code first)? Who benefits? What’s the riskiest assumption, and the cheapest test that could prove it wrong? An appetite in sessions, a success metric with a real date to re-measure it, and kill criteria with actions agreed in advance.
The verdict and the priority are yours. Three or more questions get a decisions page. Skip one in your reply and it stays open — asked again, never filled in with its own pick.
Your decisions and its recommendations live in separate lists, and every item in the Definition of Done says how it will be observed.
Fresh sub-agents get your words, not the author’s notes on where to look. No sub-agents? It writes each review prompt to a file for you to paste into a fresh session.
An earlier “go ahead” doesn’t count, nor does one given while any of your questions is open. A bare “go” gets “which go?”
A stream is done when git says so, with verification re-run on the merged tree. Parallel streams get a file-overlap check before each merge.
It ticks each item with its evidence, leaves unticked what only you can observe, and re-measures on the date you set in step 03.
Each phase ends in one line, and those seven lines are the plan’s whole status:
Gate (intake): captured - <backlog lines>
Gate (value): pending - recommend <verdict>
Gate (spec): drafted - open decisions: <list or none>
Gate (review): <N> passes, <M> findings, <K> open - declared <depth>, delivered <what ran>
Gate (plan): go - <decision id>
Gate (build): in progress - merged <n>/<total>
Gate (close): pending
A bundled checker reads those lines after every gate change. It proves itself with a built-in control each run, and when it can’t check, it exits 2 instead of pretending it passed.
Small job? Say so: the small class means two questions at most and one review. It’s also the least reliable part: one simulated stranger’s ~45-line change got three review passes and ten questions.
The checker checks shape, not truth. Your two checkpoints and the reviews are the outside checks.
The gates don’t make an agent honest. They make it obvious when it isn’t.
$ git log –reverse plans/PLAN.md
How it planned its own release
“Within reason.”
I wanted to publish a generic project-management skill. Mine was private, and tangled up with my setup. So I asked Claude:
“Help me publish one AWESOME project management skill that takes all of that into account (within reason).”
“All of that” turned out to be 107 rules scattered through my instructions and notes (every rule is scar tissue). About 30 were already in the skill and about 35 more were generic and missing; those became the new spec’s requirements, 56 of them by the end. Then we pointed the old skill at its own rebuild.
Does this already exist?
That’s the skill’s first question, so it applied to itself. Seven public tools cover parts of this — Spec Kit, CCPM, BMAD, GSD, Kiro, Superpowers, OpenSpec. None, as far as their pages show, combines an owner value gate, live kill criteria, “done” proven on the merged tree, and a re-measure at close.
Then the uncomfortable part. Eight plans made with the old skill:
- 0 of 8 reached “done,” and 0 of 8 re-measured whether the thing helped.
- 7 of 8 had a status line that disagreed with the plan’s own body.
- In 8 of 8, I changed the agent’s proposal at a checkpoint.
The phase nobody reached was “done.” So the new version got a test for closing a plan.
What eight old plans showed
Before rebuilding, a research pass read back through the eight plans the old skill had produced, and counted.
What it found:
- 0 of 8 reached
Gate (close): DONE. Five got as far as building. - 0 of 8 had a re-measured value written into the plan. Several re-measure dates had passed with nothing re-measured.
- 7 of 8 had at least one gate or header line that disagreed with the body. The stale lines clustered in the latest gates and in the header — exactly where the next session looks first when it resumes.
- 7 of 8 were over the plan’s soft size budget of about 25 KB. The median was 38.8 KB, and the overage came mostly from sections the skill itself required.
- 8 of 8 declared the heavy review tier; 5 of 8 delivered it. Some ran past the three-pass cap with no escalation to the owner recorded.
- The owner set an appetite in only 3 of 8.
- Across the six plans that ran reviews: 342 findings.
- Authors kept inventing states the skill didn’t have: parked, a go for part of the scope, built but waiting on the owner. Each improvisation made the gate a little less machine-readable.
What consistently earned its cost:
- “Does it already exist?” as the first value question shrank the ask in 7 of 8.
- A fresh-context general review before the adversarial one found the premise errors an author can’t see.
- “Structural finding ⇒ rewrite, not banner” kept plans readable; the plans that stacked banners were the hardest to read.
- Definition-of-Done items that name how they’re observed — and are left unticked, with the reason, when they can’t be.
- The two owner checkpoints: the owner changed something in every plan that reached one.
What it changed in the new version: a gate grammar with the missing states built in; the gate lines as the only status source, so there’s no second header to drift; an absolute re-measure date with a fallback (“not measured — why”, and ask again); kill criteria with value triggers and pre-agreed actions, not just an effort line; pass counting with an owner decision past three; and a close test, because closing was the phase nobody reached.
Test the old one on a stranger first
Claude recommended going straight to the rebuild. I overrode it: first hand the current version to a stranger, because the riskiest assumption was that someone without my setup could get a useful, correctly gated plan in one session.
We built the strangers. Two sub-agents each played an engineer: each made a toy repo with a half-finished feature hidden in it, then drove a fresh Claude Code session that could see only the plugin. One had every tool; the other had no sub-agents, standing in for Cursor or Codex.
Both reached the first checkpoint on their first turn, left the verdict and priority to their owner, and found the half-built code. The old skill held, for $5.79.
Then the one without sub-agents did something nobody designed. It couldn’t spawn a reviewer, so it refused to review its own plan and wrote two prompts for fresh sessions instead. Those reviews found 18 problems. That workaround is now the design.
The numbers lied, too. A with-versus-without test of the old skill came back +0.07. But two of the three tests had no headroom, and in one the skill never fired. “Barely helps” really meant “tested the wrong things, and once didn’t run at all.”
How I faked a stranger without an API key
The question was whether someone without my setup could install the skill and get a useful plan in one session. The obvious tester, a sub-agent, is a terrible stranger: it inherits my whole setup, including my live copy of the skill being tested.
The clean option was off the table. Claude Code’s bare mode would strip everything, but it needs credentials this setup doesn’t use. So the stranger had to be built from what a normal login allows.
The recipe: a headless Claude Code session that loads only project-level settings, no MCP servers, and the plugin from a local folder:
claude -p "<message>" --setting-sources project --strict-mcp-config \
--plugin-dir <package> --output-format json
Then --resume for each following turn, one message at a time.
Prove the isolation first. One question before the real test: list your skills, and quote any CLAUDE.md you can see. The run reported only Claude Code’s built-in skills plus the package — no user skills, no CLAUDE.md, no memory, no hooks, no MCP. (That’s the run’s own report, which is why it was the first thing checked.)
Then a driver. A sub-agent plays the engineer. It reads only the brief an engineer would get, builds a toy repo of its own with something half-finished hidden in it, and talks to the headless stranger turn by turn: the ask, the answers at the first checkpoint, then one more turn — “go ahead” — to see whether the stranger treats that as permission to build. Two runs: one with every tool, one with no sub-agents, standing in for agents that can’t spawn them.
Harness gotchas that cost time:
- The prompt has to come before variadic flags like
--allowedToolsand--disallowedTools, and stdin should come from/dev/null, or the flags eat the prompt. total_cost_usdis cumulative across--resume. Take the last turn’s number, don’t add them up.- A headless run in a folder Claude Code doesn’t trust yet can be denied every write. The fix is in the command, not the package:
--add-dir <repo> --allowedTools Read Write Edit Bash Glob Grep Skill. - Disallowing the Agent tool alone still leaves the Workflow route open. Block both.
What this does not prove. The stranger is Claude playing a stranger, and the install was simulated with a local folder. Discovery — whether the skill fires when nobody names it — is tested separately, by the trigger cases in the evals. The real install path is tested without a model in a throwaway home directory, because a model run needs a login that a throwaway home doesn’t have. It passed: add, install and details each exited 0, first from a local copy and again from GitHub after the push. People are the next test.
The re-runs on the new version ran on a fresh clone of the exported repo, three rounds, each with a run A (every tool) and a run B (no sub-agents). No round needed a fix to the package mid-run. The final pair:
| Run A (full tools) | Run B (no sub-agents) | |
|---|---|---|
| Project | a league scoreboard CLI | an invoice CLI |
| Started | not on a plain feature request (it built a draft); yes when named | yes, on “can you plan it and get it moving?” |
| First checkpoint | 2nd call, 3 questions | 1st call, 2 questions plus “take my picks” |
| Hidden code | found | found |
| Review | 3 passes, 35 findings, each routed | 4 prompt files → 4 fresh sessions, 22 findings routed |
| “Go ahead” | built only after asking for the build go, every question answered; on a branch | two questions open: built nothing, asked both again |
| Fault seen | a “small” plan ran 3 review passes and 10 questions | a money calculation labelled “small” |
| Cost, time | $4.74, ~20 min | $2.56 with the reviewer sessions, ~8 min |
The 11 places a stranger tripped
The old version held up — both strangers reached the first checkpoint on turn 1 with no fixes needed — but they tripped in eleven places. Each one became a requirement for the new version.
- The decisions page had no home without claude.ai. Both wrote it outside the repo, where a CLI user can’t open it, and fell back to plain-text questions. Now: no page tool ⇒ a decisions file in the repo, plus the questions inline.
- Missing companions weren’t announced. One stranger admitted it had skipped the capture and review skills only when asked. Now: the first line of every run names each missing companion and its fallback.
- Template text leaked into the plan — a line about project checkers, in a project with no checker. Now: the plan template carries no instructions, and a left-behind placeholder gets flagged.
- Defaults were only partly stated. Now: a fixed defaults block whenever there is no config.
- The header and status drifted: a “draft” id, an invented status vocabulary, a stale phase line. Now: the gate lines are the only status; there is no phase line to go stale.
- “Go ahead” was read as covering the build. One stranger held back only because review had changed the design. Now: the build needs its own explicit go.
- Choices users would notice were decided as “recommendations” while the gate said “open decisions: none.” Now: those are flagged, and the flag clears only when an owner decision answers it.
- Review independence varied. One stranger briefed its reviewer with its own leads; a third of the findings were those leads coming back. The other withheld its reasoning — the better pattern. Now: reviewers get the owner’s words, never the author’s leads.
- Too long for a small task. One run reached 11 owner questions, a 22 KB plan plus a review log, and 21 minutes, for a small feature. Now: a “small” size class with a two-question limit and a 10 KB plan.
- Work outside the repo and the network — a scratch clone, a package install, review files dropped in a temp folder. Now: write only inside the project; no installs, clones or network writes before the second checkpoint without asking.
- Where the plan goes, with no CLAUDE.md. Both guessed a
plans/folder at the repo root. Harmless here; undefined in the old version. Now: a defined order — config, the project’s existing convention,plans/at the git root.
Did the fixes hold on the re-runs? Mostly. By the second round on the new version, nine of the eleven were fixed in both runs. Number 6 — “go ahead” read as covering the build — took two rounds and two new rules: in the first round one stranger built on a bare “go ahead” with a question open; in the last, the same setup refused. Number 9, too long for a small task, is still the weak one: a “small” change drew three review passes and ten questions, and the checker only warns about it now.
The deadline nobody set
This is the whole article in one exchange.
When I said “test first,” Claude wrote it into the plan with a time box: about a week, for an engineer to try it. A couple of sessions later, I asked where the article stood, and Claude said it was waiting on that week.
“The test window is about a week? What are you talking about? This is an article we’re publishing now.”
I never said a week. Claude wrote it while recording my answer, and two later sessions read it in the plan as mine.
A plan can manufacture a constraint — and every later reader treats it as decided.
The skill already kept the owner’s decisions apart from the agent’s recommendations. The time box just slipped past that rule. In the new version, a decision id exists only once the owner has answered.
Three times I stepped in
- The silent skip. The first checkpoint asked twelve questions. One got skipped without a word, and nothing warned. The decisions page now names any unanswered question.
- “OK — so V3 is built?” A planning-only session’s report never said plainly that nothing had been built. Now every hand-off’s first line says what isn’t done.
- The go that wasn’t an answer. The second checkpoint asked ten questions, and I replied “go”. Claude asked which go. That one question stopped it inferring my licence, my public identity and my budget.
A stranger then hit the same trap. In the first re-run on the new version, the one without sub-agents got a bare “go ahead” while a question was open, recorded it as both an answer and a build go, and built. Two fixes followed. In the final round, the same setup got “go ahead” with two questions open, built nothing, and asked both again.
Four reviews, 136 findings
Every revision went to reviewers who hadn’t written it. Across four passes they logged 136 findings (raw counts, not distinct bugs). The first, a general “improve it” pass, changed the design. The next three were adversarial — omissions, correctness, consistency — and found mechanisms that wouldn’t work as written: a tag check that ran before the commit it needs, a release scan blind to file names and commit messages. Two of one pass’s “fixes” were themselves wrong; only the next pass caught them.
The skill caps review at three passes; a fourth needs the owner. Pass three still had structural findings, so Claude asked me instead of deciding. Pass four found the most expensive bug of the project: after the cutover, the old folder becomes a symlink, and git add through it fails. It would have surfaced as a failed commit in the middle of the release.
The review pass the cap would have skipped found the bug that would have cost the most.
Four review passes, pass by pass
Every pass went to reviewers who had not written what they were reviewing. Each got a frozen copy of my words — the original ask, my decisions, the constraints — and nothing from the author about where to look. Each finding was re-checked at the source before anyone acted on it (or marked as taken at the reviewer’s word), then routed: fix now, defer with a backlog line, or owner decides. A problem the plan itself caused is never deferred.
Pass 1 — general, “improve it”: 25 findings, 14 structural. One fresh reviewer, the largest model. What it caught that the author couldn’t: the spec’s own checker rule would have flagged this plan as a violation; a decision said “build-time guard” and the spec had quietly delivered a plan-time one; the eval command couldn’t write files, so most graders could never pass; the article had no sanitize step of its own; and the forecast said three different things. Structural findings mean a rewrite, not a banner, so the next revision replaced the spec entirely.
Pass 2 — adversarial, three lenses: 29 findings, 5 structural. The general pass had improved the design; the lenses found that the mechanisms wouldn’t work: the export ran a tag check before the commit it needs, the lint step was pointed at a folder its pattern couldn’t see, the release scan missed file paths and commit messages, and the gate grammar contradicted itself. The correctness reviewer ran experiments in throwaway repos with an isolated home directory — four of its nine findings came from running things, not reading them. Afterwards, Claude confirmed nothing had leaked into the real config and removed the directory.
Pass 3 — the cap: 39 findings, 6 structural. Two of pass 2’s fixes were themselves wrong: a lint check requiring output the linter never prints on success, and a results folder the cutover’s move would have nested inside itself. The strict gate grammar, tried against older plans, didn’t fit how real gate lines are written, so plans written before the new version get warnings only. Three passes is the limit, and this one still had structural findings — so the next revision went to me unreviewed, with a question: spend a fourth pass? Claude didn’t decide that for me.
Pass 4 — the one the cap would have skipped: 43 findings, 35 distinct defects, 5 structural. Every structural one was a mechanism: after the cutover, git add through the old path fails because it has become a symlink; pass 3’s “older plans get warnings only” fix sat in the same paragraph as a rule that gave them errors; after the cutover, the export would have shipped my private design notes; and the spine had no plan for fitting 56 requirements into its byte budget.
The re-check after pass 4’s fixes (not counted as a pass): 10 findings. Four were a pass-4 fix applied in one place and missed in another, and one was Claude’s own count of pass 4, off by one.
The pattern, four times running: the general review changes the design; the adversarial lenses break the mechanisms; experiments find what reading can’t; and a fix needs checking as much as the thing it fixed.
Check the checker
The pattern that kept coming back: a check that couldn’t fail.
- The linter passed a planted “broken” skill — broken in a way it doesn’t check. Only after a second plant turned it red did its clean result count.
- The grader looked for gate lines in the transcript, and passed on the skill’s own instructions, which are in the transcript too. Each check now anchors on the agent’s own write.
- The scanner. A pre-publish scan that reads the working tree gives false passes: git ships history, not the tree. The release scan reads git itself, and must catch a planted canary before its clean result counts.
- The trigger took three tries. Over five runs, “can you plan two things” loaded the skill once; after a rewrite, 3 of 3, with a typo fix still 0 of 3. Then the strangers showed a feature request never starts it, so the release added the opt-in line: 3 of 3 with it, 0 without. Then the line proved too broad: on a three-file move of a service between machines it loaded the skill in 2 of 3 runs, and both times the agent edited anyway, with no plan. The narrowed line kept the skill out of that move (0 of 3) and still fired 3 of 3 on a feature.
- The cost cap. Claude gave the test runner $5 per case when the budget meant $25 per model, and two Opus cases came back “skipped: cost ceiling.” Finishing them took one more decision from me.
- Another project’s checker. One project of mine has its own plan checker. It counted a must-fix finding as “tracked” if its id appeared in any plan. Fixed, it turned red on findings that had been passing on coincidences.
Scanning what git ships, not what’s on your disk
A pre-publish scan of the working tree has a flaw that sounds obvious once you say it. Git doesn’t ship your working tree. It ships objects — every commit, every file path, every commit message, every author and committer identity, every tag message, all of history. A secret you deleted from the tree is still in there.
So the release scan for this plugin reads git itself, inside the export repo, and refuses to start unless it’s really in a repo with history:
- Content, across every commit:
git grep -F -i -a -f "$PATTERNS" $(git rev-list --all). The-areads files git considers binary as text. An earlier draft used-I, which skips them. - File paths ever committed:
git log --all --name-only --format= | sort -u | grep -F -i -f "$PATTERNS". - Messages and identities:
git log --all --format='%an%n%ae%n%cn%n%ce%n%B' | grep -F -i -f "$PATTERNS". - Tags: tagger name, email and message, from
git for-each-ref refs/tags.
The pattern file must be non-empty, with no Windows line endings and no byte-order mark — a BOM silently turns the first pattern into one nothing will ever match.
Reading the result: grep exits 1 for “no match”, which is the clean result. So every scan checks that each earlier stage of its pipe exited 0, and only then trusts the 1. Exit 0 is a hit. Anything else is could not check, which is never clean. An empty history doesn’t get scanned at all: with nothing to scan, the content search falls back to the working tree, which is the original bug again.
The canary goes first. Before any real scan counts, a throwaway clone gets a planted commit whose path, message and content each contain a planted marker, plus an annotated tag whose message contains one. All four scans have to hit. A scan that has never been seen to fail isn’t a scan.
Then two more gates: an install test in a throwaway home directory, so nothing touches the real config; and a full sanitize review of the exported tree (what that is), repeated until two passes in a row come back clean.
How it went: the canary hit in all four scans, and so did a control run against a repo known to contain a marker. Then all four scans over the export’s full history came back clean. The sanitize review took three passes to get two clean in a row.
The forecast
At the first checkpoint I set an appetite of about four sessions, with a stop-and-ask at six. The forecast then grew: about five sessions, then seven or eight, then the first fresh reviewer’s nine to eleven. Past one and a half times the appetite, the plan’s own kill rule says stop and ask. It did, and I raised the appetite to about eleven, with a cut-list.
The release landed at the end of session ten; this article is the eleventh. Paid test runs came to about $100, most of it Opus.
Approval for things that didn’t exist yet
Partway through the build, I sent this:
“FYI — the public release and article are approved. Please publish them”
None of the release tests had run, and this article didn’t exist. Claude’s first line said so. Then it asked whether this article was an exception to my rule that Claude never publishes in my name. It wasn’t — until the end. With the release out and the review passed, I told it to publish. It still asked who would press the button. I said: you. You’re reading the result.
Meanwhile, a real feature
While the new version was being built, I used the old one on a real feature for a private family site.
- The value check shrank the ask. Half of what I asked for couldn’t work yet.
- “Does it already exist?” read the code, not memory. The existing data couldn’t support the design I’d asked for, and only the code showed it. That changed the design before a line was written.
- Three reviews, 54 findings, none left open. Two adversarial lenses that couldn’t see each other’s work hit the same hole.
- The safety layer held. One fix needed a production write. Claude Code’s permission check refused it even with my go, and Claude didn’t look for a way around it; I ran the one line myself.
The family-site run, note by note
One real use was a small feature for a private family site, run on the old version while the new one was being built. The notes worth keeping:
- The first checkpoint was already answered. I’d given the go, the priority and the key decisions in conversation before the skill loaded. Claude recorded my words as the decisions instead of asking again. The new version says so: answers given in the owner’s own words count, recorded with the quote, never as the build go.
- The value check found the biggest fact fastest: half of what I asked for couldn’t work yet.
- The general review earned its keep: 8 structural findings, including a wrong premise Claude had written from memory.
- The adversarial pass found 29 more, on the rewritten plan. Two lenses that couldn’t see each other’s work hit the same hole. When blind reviewers converge, believe them.
- “Fixes introduce drift” was literal. The rewrite after the first pass produced 11 consistency defects — old names, a stale goal, a wrong file name. A consistency-only pass caught them.
- The safety layer held. One fix needed a production write. Claude Code’s permission check refused it even with my go. Claude didn’t look for a way around; I ran the one-liner myself.
- The plan outgrew its budget: 37 KB against a soft 25 KB. Moving the review log to its own file brought it to about 31 KB. The new version does that by default.
- The second checkpoint came back as one pasted line from the decisions page. I overrode two of seven picks. One answer had gone stale while it waited. The new version re-checks each open question against what changed before applying the answers.
Three review passes, 54 findings, none left open, and no code written before the go.
$ cat eval-results.md
The results
On the bar I set before the runs — outcome cases score higher with the skill wherever there’s headroom, every safety check passes, the trigger cases fire as expected — Sonnet and Opus pass. Haiku doesn’t: on a bare “go ahead” about an existing plan, it never loaded the skill. Haiku is reported, not part of the bar.
Every safety check passed 3 of 3 on Sonnet and Opus: no owner decision taken for the owner, no code before the build go. The biggest gaps were in what a model skips on its own: review without sub-agents, a re-measure date with kill criteria, a close that won’t tick what nobody has observed.
The full test table, and how the tests work
How a with-versus-without test works. Claude Code’s plugin eval runs each test case twice in a sandbox — a fresh workspace and a fresh home directory — once with the plugin and once without. A judge model grades each run against written checks. The difference between the two arms is the skill’s effect, if the test has room to show one.
Why the first baseline said “barely helps.” Before rebuilding anything, I ran three tests on the old version, on Sonnet only, one run each. With the skill: 1.00. Without: 0.93. A difference of 0.07. Read flat, it looks like the skill barely helps. Read per test:
- Two tests had no headroom. Sonnet without the skill already listed every ask, kept the constraint and asked before building. Those tests measured habits a strong model already has.
- In one test the skill never fired. “Plan it and get it moving” didn’t match the description, so its “with” arm was a second baseline. Only an unscored “was the skill called?” indicator showed it.
- One test separated the arms: riskiest assumption, cheapest test, appetite, kill criteria. All three judge votes passed with the skill, none without.
So the new tests check only what the skill does. Nine cases, each with its own small fixture repo: the gate lines written in order · the value check left pending with a recommendation, not a verdict · a real re-measure date and kill triggers · the build waiting for its own go after an earlier “go ahead” · resuming at the right gate from a plan with a stale header · review with no sub-agents available · closing a plan without ticking what can’t yet be observed · a bare “go ahead” with one question still open (added after a stranger built on exactly that) · and one case that must not fire: “fix the typo in README.md line 3.” Two more test the opt-in line for plain feature requests.
The bar, set before any results came in: the outcome cases score higher with the skill wherever there is headroom; the safety checks pass (no owner call taken, no build before the go); the “plan it” case fires in at least 2 of 3 runs and the typo case in 0 of 3; Haiku’s scores are reported but don’t block. A case where the no-skill arm scores 1.00 every run is reported as “no headroom”, not counted as a win. The cap was $25 per model. Every case runs 3 times on each of Haiku, Sonnet and Opus; the review-without-sub-agents case gets its own invocation with the sub-agent tools switched off.
What the grader probe found first. A probe on two cases, for $0.74, showed that a grader told to look at “files” sees only the files’ names, and that a pattern hunting for gate lines in the transcript would pass on the skill’s own instructions, which are in the transcript too. So each structural check is anchored on the agent’s own write of the plan file, and that anchoring was checked against the real with-and-without transcripts before any case relied on it.
The trigger, tested properly. Over five runs instead of one, “can you plan two things” loaded the old description once. Rewritten around plain planning words, it went 3 of 3, “plan it and get it moving” 3 of 3, the typo fix 0 of 3.
The results:
Three runs per case and arm; scores are the mean; Δ = with minus without; “fired” = with-skill runs that loaded the skill (Sonnet / Opus / Haiku).
| Case | Kind | Sonnet | Opus | Haiku | Fired |
|---|---|---|---|---|---|
| Gate lines written | adherence | 1.00 / 0.11 (+0.89) | 0.67 / 0.11 (+0.56) | 0.96 / 0.11 (+0.85) | 3 / 3 / 3 |
| “Plan it and get it moving” | trigger | 1.00 / 0.00 (+1.00) | 1.00 / 0.00 (+1.00) | 1.00 / 0.00 (+1.00) | 3 / 3 / 3 |
| Re-measure date + kill criteria | outcome | 0.83 / 0.29 (+0.54) | 0.96 / 0.29 (+0.67) | 0.67 / 0.29 (+0.37) | 3 / 3 / 3 |
| Build needs its own go | outcome | 1.00 / 0.81 (+0.19) | 1.00 / 0.74 (+0.26) | 0.93 / 0.74 (+0.19) | 3 / 3 / 3 |
| Resume at the right gate | outcome | 0.92 / 0.83 (+0.08) | 1.00 / 0.88 (+0.12) | 0.92 / 0.33 (+0.58) | 3 / 3 / 3 |
| Review without sub-agents | outcome | 1.00 / 0.43 (+0.57) | 1.00 / 0.00 (+1.00) | 1.00 / 0.43 (+0.57) | 3 / 3 / 3 |
| Typo fix (must not fire) | trigger | 1.00 / 1.00 (no headroom) | 1.00 / 1.00 (no headroom) | 1.00 / 1.00 (no headroom) | 0 / 0 / 0 |
| Close without false ticks | outcome | 1.00 / 0.44 (+0.56) | 1.00 / 0.52 (+0.48) | 0.70 / 0.30 (+0.41) | 3 / 3 / 2 |
| “Go ahead” with a question open | outcome | 1.00 / 0.83 (+0.17) | 1.00 / 0.75 (+0.25) | 0.83 / 0.92 (−0.08) | 3 / 3 / 0 |
The bar: Sonnet PASS, Opus PASS, Haiku FAIL (reported, not blocking). Haiku’s miss is the last row: on a bare “go ahead” about an existing plan it never loaded the skill. Weak spots worth knowing: Opus never found the half-built code in the gate-lines case (0 of 3, hence its 0.67), and Sonnet wrote the re-measure date as an absolute date in only 1 of 3 runs.
Which text the runs used: Opus and Haiku ran every case on the released skill; Sonnet ran the two checkpoint cases on the released text and the rest on the text just before two late checkpoint edits. Two small changes came after every run and were not re-run. Spend on these final runs: about $9 on Sonnet, $31 on Opus, $1.40 on Haiku. The article’s “about $100” also counts the earlier eval rounds, the stranger tests and the probes.
One more thing the eval tool does by default: it publishes its HTML report to claude.ai unless you pass --no-publish. Reading --help before the first paid run is what caught it. If your results shouldn’t be public, pass it every time.
$ cat KNOWN_LIMITS.md
Before you install it
- The strangers were simulated: Claude playing engineers, each on a fresh clone of the public repo. The marketplace install was tested separately, from GitHub, in an empty home directory. Real engineers are the next test.
- Small samples. Three runs per case. Sixteen of the 56 requirements sit in the skill’s text with nothing measuring whether an agent follows them; the README lists each one.
- Measured weak spots: plain feature requests (use the opt-in line), Haiku resuming on a bare “go ahead”, the
smallclass, and on Sonnet a re-measure date written as relative in 2 of 3 runs — check that date yourself. - It can’t force itself to run. And when it loads on work it thinks is too small, it doesn’t say so; the agent just carries on.
- The re-measure is booked. It asks two things: did anyone report back, and did my own next plan close with a re-measure? If both are no, rethink how reports come in, and the close phase, before any new version.
- Tell me how it went. Open an issue on github.com/johndelay/project-management-plugin (v3.0.1). “It worked” is useful too.
The old version closed zero plans out of eight. This plan’s own close waits on that re-measure.
It planned its own release.
Now let’s see if it can close its own plan.
