Repository navigation
Releases: LuisFelipeMoro/Harness-devkit
Release list
v2.8.1
Changed
- /multi-agent and /task recommend the thin orchestrator. When the session is not running as
claude --agent orchestrator, they print the exact relaunch commands once and never block:
/multi-agentalways,/taskonly when the blast radius is big. The main session carried most of
the delivery's cost (measured on one delivery).
v2.8.0
Go idioms that are checked against the module's own Go version, a latency method that starts with a
trace, a fan-out rule that lets read-only work run wider than writes, and an opt-in stance on agent
teams, plus leaner dispatches. Five stories, each judged on its own.
Added
- Version-gated Go idioms.
references/go-modern-idioms.mdtabulates Go 1.18–1.26 idioms. Each
row carries its minimum Go version and applies only when the module'sgodirective reaches it. - Advisory modernize gate.
go fix -diff(Go ≥ 1.26) is a row in both quality-gate references.
QA and/quality-gatereport it as ADVISORY or skipped; it never fails a gate. A wiring check rejects an unpinned fetch. - Named contract rows.
validate-wiring.pygainscontract_check(name, …), so a failing row
printsFAIL: <name>and can be falsified withbreak-run.sh. - Trace-first latency budget.
references/latency-budget.mdtraces one slow request before it
picks a fix by layer./performance-profilingroutes to it when latency is spread across services. Fixes chosen from the budget return to steps 4–5, so a characterization test pins current behaviour before the first change. - Cross-layer fixes. The performance-profiling fixes table gains five rows: pool sizing, owned
caches, chained service calls, async off-path work, and payload size. There are no millisecond
thresholds; targets come from the service's SLO. - Architect design fields. The Architect template gains a remote-calls-per-request field and a
cache-owner field, so latency is decided at design time. - Agent teams, documented and off.
references/agent-teams.mdrecords what the experimental
flag does to dispatch and the only way the devkit tolerates it: read-only lanes, with the flag
never set by the installer. CLAUDE.md points to it. - Leaner dispatches. Pipeline agents declare a
tools:allowlist: a measured probe fell from
41.5k to 14.9k tokens of inherited tool definitions. Dispatch rules forbid resuming an agent
except for a QA re-audit, because a resumed transcript replays in full. Small doc-only manifest
rows bundle into one row. An opt-in thin orchestrator (claude --agent orchestrator) keeps the
main session off file reads, andbench-context.py --manifestprints a main-session estimate.
Changed
- Validators cannot edit. qa, reviewer, stress, verdict and plan-reviewer list no Edit or Write
tool, andvalidate-wiring.py(tools_check) fails the build if one gains either. They keep Bash
for running gates, so this is a tools-list rule, not a sandbox. - Read-only fan-out has its own width. Writers stay at three per turn. Read-only subagents (no
Edit or Write tools, a no-mutation prompt, no mutating shell command) get a separate width in
thresholds.md. Contracts are frozen before fan-out, read-only dispatches may run in the
background while the gate chain stays in the foreground, and every dispatch still counts toward
the session budget. The escalation ladder applies to writers only. - Model aliases are named as the source of truth. The model table pins no version: the
opus,sonnetandhaikualiases resolve to the newest model in each family, and the two skills
that restate the table defer to it.
Credits
- Idea sources, paraphrased (no text copied): JetBrains/go-modern-guidelines (Apache-2.0) for the Go idiom table, and danicat/skills (Apache-2.0) for the read-only fan-out, contract-convergence and return-cap rules.
Versions
| Plugin | Version | Why |
|---|---|---|
coding-pipeline |
2.7.1 → 2.8.0 | Go idioms and advisory modernize gate, latency budget, read-only fan-out width, agent-teams reference. Additive: no rule a consumer relies on is removed. |
engineering |
1.5.1 → 1.6.0 | Advisory modernize row in the gate reference, guarded against an unpinned fetch. |
v2.7.1 — Hook installer works from a git worktree
Fixed
- Installing from inside a git worktree aborted half-way.
git-hooks/install.shcopied hooks to
<toplevel>/.git/hooks/, but in a linked worktree.gitis a file, socpfailed with "Not a
directory" andset -estopped the whole devkit install at step 3/5. Hooks now go to the repo's
common git dir (git rev-parse --git-common-dir), which every worktree shares, and the success
message prints where they actually landed.
Versions
| Plugin | Version | Why |
|---|---|---|
coding-pipeline |
2.7.0 → 2.7.1 | Hook installer fix. |
v2.7.0 — Diff-scoped story loop and harness guards
Half the subagent dispatches for the same guarantees, and a set of guards that close the ways a
pipeline run went wrong while it was being built. The first half is a measured change to the story
loop; the second is what running that loop on real work taught.
The study: where does a delivery's cost go?
Question. A delivery spends tokens in two places: the guides each dispatch loads, and the number
of dispatches. v2.6.0 measured the first and cut it 3.5%; the dispatch graph was untouched at 40 per
five-story delivery. Which of the two is worth changing?
Method. scripts/bench-context.py models the dispatch graph and the guide tokens each path
loads, run against the v2.6.0 tree and the new one. Per-agent costs come from real dispatches, not
estimates: every agent run in this release was logged with its token count.
Result.
| Per five-story delivery | v2.6.0 | 2.7.0 | Change |
|---|---|---|---|
| Subagent dispatches (uniform roster) | 40 | 20 | −50% |
| Subagent dispatches (mixed rosters) | — | 18 | |
| Guide tokens loaded | 244,170 | 216,309 | −11.4% |
The mechanical sensors read far less than an agent would: a security scan prints 365 tokens where
the changed files are 66k (182×), a tautology scan 65 where a 38-file test suite is 52k (797×), the
duplication gate 91 where raw jscpd output is 6.8k (75×).
Why it moved. Dispatches fell because work that was agent judgment became arithmetic or a
sensor: the verdict is verdict.sh, not an agent; story generation for a one-row manifest is a
template fill; the story-level PR review read the same diff the Reviewer had already read; Stress
runs only when the diff warrants it. Validation reads the story's diff, not the tree.
What the model does not show. Fix rounds. The estimate counts first passes; on stories that ran
the full roster, rework added 40–60% on top. The guide-token saving also shrank from −14.2% to
−11.4% once the rules below were written into every agent's guide — a deliberate trade of tokens
for guarantees, measured rather than assumed.
Added
- Rosters. Each story declares a roster —
cosmetic,light,standard,full— and it
decides which agents run. Mechanical gates run on every roster without exception.
classify-diff.shchecks the declaration against the real diff and only ever escalates: a file
that looks like style but holds code, a rename that disguises code as style, a symlink, or a
deleted source file cannot lower the roster. - One-command mechanical checkpoint.
checkpoint-m.shruns every mechanical check a story must
pass and reports every failure at once: spec rows by exact name, the exact changed-file set
(renames count both paths, deletions count), no commits beyond the base, no leftover
falsification markers, the roster, the repository's gate command and duplication. A sub-check
that cannot measure fails closed. No agent validates code this checkpoint has failed. - Self-restoring falsification.
break-run.shapplies one literal mutation — refused unless it
matches exactly once — requires the named test to fail by its own name, and restores the file
byte for byte on every exit it can trap, keeping the pristine copy if a restore ever fails. It
refuses symlinks and paths outside the repository and locks the file against concurrent runs. - Release-content guard. Session memory, handoff notes and generated test output are rejected
from commits and pushes by path, from patterns in a committed.devkit/release-exclude. Every
published commit is checked, merge commits included; a git failure blocks instead of passing. - Execution-options checkpoint. After a plan is approved,
bench-context.py --manifestshows
the operator dispatches and a token range per option — with first-pass and with-rework figures,
each cost labelled measured or assumed — and no code starts until one is chosen. - Oversized-prompt warning.
dispatch-budget.shwarns when a single agent prompt is too long or
names too many files; oversized prompts were the cause of every agent stall observed.
Changed
- The story loop validates the story's own diff, dispatches by roster, runs the Reviewer and Stress
in parallel after QA, and re-checks narrowly after a fix. The verdict isverdict.sh. - Agent guides carry scope rules: edit only the listed files, never revert work you did not make,
probe only under$TMPDIR, falsify throughbreak-run.sh, make every error path fail closed and
test it. An agent's report is a claim; the evidence is what the checkpoint reproduces. PROGRESS.mdis local session memory: git-ignored and never committed.
Lessons behind the guards
Each failure class below was observed while building this release; each has a guard or a rule.
| Failure | Guard |
|---|---|
| An agent reported work or evidence that did not exist | checkpoint-m.sh checks rows by name and the exact file set; the orchestrator reproduces evidence with break-run.sh |
| A test failed without naming itself, or passed for the wrong reason | break-run.sh accepts only a failure that names the row |
| An agent died mid-test and left code deliberately broken | Break markers; the checkpoint fails while one exists |
| A mutation hit a comment instead of code and proved nothing | break-run.sh refuses a pattern that is not unique |
| An agent committed, reverted or created files outside its scope | Exact file-set and commit checks; scope rules in every guide |
| A check that could not measure reported a pass | Every sensor exits 2 (unmeasured) on a failure it cannot see past |
| A classifier trusted a file's name over its content | Content is scanned before a roster is ever lowered |
| Oversized prompts stalled agents | The prompt-size warning; split large dispatches |
| Estimates ignored rework | Rework factors in the execution-options table |
| A timing bound held only on an idle machine | Test waits are sized for a loaded machine |
| Session notes shipped in a release | The release-content guard |
Still open: an agent told to work in a worktree can edit the main checkout instead. A guard that
refuses edits outside the active worktree is the next change.
Versions
| Plugin | Version | Why |
|---|---|---|
coding-pipeline |
2.6.0 → 2.7.0 | Rosters, new verify scripts and guards (features). |
devtools |
1.3.0 → 1.3.1 | handoff docs: PROGRESS.md is git-ignored, never committed. |
engineering |
1.5.1 | Unchanged. |
pr-workflow |
1.5.1 | Unchanged. |
v2.6.0
Token and dispatch cost, cut without weakening a guarantee. Three rules the devkit stated and never
enforced now have sensors, the mechanical half of three agent audits became scripts, and the 80%
context ceiling stopped needing a human to act on it.
Added
- Context and dispatch sensors.
hooks/context-budget.shreads real context fill from the
session transcript (prompt + cache + the last turn's output, subagent turns skipped) and warns at
60% / calls the ceiling at 80%. The model no longer reports a number it cannot measure.
hooks/dispatch-budget.shcounts subagent dispatches per session and warns once past 14
(3 per story × 3 + 3 planning + 2 delivery). Neither ever blocks. - Autonomous context loop. At 80% the instruction is now checkpoint and continue: update
PROGRESS.md, commit and push, carry on. The newPreCompacthookprecompact-snapshot.sh
records branch, dirty files, last commits and whetherPROGRESS.mdwent stale; on
source=compact,session-bootstrap.shre-injects it for the same session only and re-arms the
60/80 latches. The window is inferred (usage past 200k means 1M) unlessDEVKIT_CONTEXT_WINDOWis
set. No step waits for a person to open a new session. - Mechanical verifiers in
scripts/verify/:spec-coverage.sh,falsification.sh,
tautology-scan.py,security-scan.sh,verdict.sh. Each replaces the lookup half of a QA,
Reviewer or Verdict pass and prints what it does not cover, so the judgment half stays with the
agent. Unreadable input exits 2 (UNMEASURED) — never a PASS. Measured read-avoidance: 22× to 797×. git-hooks/dup-gate.sh— the one owner of jscpd's flags and line-level attribution. pre-push
calls it;--worktreemeasures uncommitted work in a throwaway worktree, so/quality-gategives
pre-push's verdict before anything is committed.references/thresholds.md— every numeric gate in one place. The coverage floor had been
restated in 18 files and had already drifted in one.scripts/bench-context.py(guide tokens per delivery) and.github/scripts/test-verify.sh,
wired into CI: the verify scripts replaced model passes, so nothing else checks them.
Changed
- Seven guides told agents to run raw repo-wide
jscpd, which counts markdown and pre-existing
debt and disagreed with the hook. They now point atdup-gate.sh. qa.md,reviewer.mdandverdict.mddelegate their mechanical checks to the scripts; the
security test-case table loads on a scan hit or an I/O/auth surface, and QA states which.verdict.shenforces the per-story floor (Reviewer and Stress ≥ 7) that the average could hide.
Fixed
install-global.shaborted underset -ewhen any directory — a gitignored__pycache__—
sat ingit-hooks/, silently skipping every step after it, settings wiring included. Only files
are copied now.- The git-hook test suite and the duplication report used fixed temp paths; concurrent runs deleted
each other's files. Both are per-run now.
Full Changelog: v2.5.1...v2.6.0
v2.5.1 — remote tag deletion as its own guard case
What's Changed
Fixed
-
destructive-guardtreated every remote ref deletion as a branch deletion. Deleting a remote
tag tripped the branch-deletion block, which surfaced while cutting v2.5.0: the guard refused a
legitimate tag cleanup, and working around it would have defeated the point of having it. The two
are different risks — a deleted branch can take unmerged commits with it, while a deleted tag is
recovered by re-tagging the same SHA.Tag deletion is now allowed only when every deleted ref is spelled out as
refs/tags/. The
explicit form is the operator stating intent, so the ambiguous shorthands stay blocked:-d,
--delete <name>and:<name>all still fail, as does any refspec touchingrefs/heads/—
including a mixed push that would delete a tag and a branch together. Falsified by reverting the
guard and observing the two allow-cases turn red. Hook tests: 42, up from 37.
Full Changelog: v2.5.0...v2.5.1
v2.5.0 — Go concurrency & testing standards + skill-surface single source of truth
What's Changed
Two sources: the GopherCon Latam 2026 workshop material (concurrency + modern Go testing) and the
skill-optimizer standard from the skills.danicat.dev catalogue.
Added
-
Go concurrency rules for the defects
-racecannot see. Transaction races (check-and-act
split across two critical sections), lock ordering by stable id, never holding a mutex across
I/O, cloning before returning references to guarded state, theLockedsuffix with
+checklocks, result channels buffered to sender count,deferplaced at acquisition,
errgroupclosures usinggctxrather than the outer context, and atomics limited to a single
read-modify-write. A data race is caught by the race detector; a transaction race has every
access synchronised and the sequence wrong, so a green-racerun is not evidence against it. -
A
Concurrency Tool Fittable naming the right primitive per problem and the
overengineering signals — an actor where a mutex suffices, a pipeline whose stages relay values,
errgroupwhere no goroutine returns an error. This is CD2 expressed in Go primitives, wired to
one MINOR review flag. -
Modern Go testing rules: no
time.Sleep, test-scoped contexts, cleanup registered at
acquisition,b.Loopwithb.ReportAllocs(),benchstatover-count=10runs rather than
eyeballed single runs, fuzz corpus discipline (diverse seeds,t.Skipfor out-of-domain input,
panic-safety separated from property targets, committed crash files),fstest.TestFSand
iotest.TestReadercontract tests, deterministic failure stubs, and goroutine-leak assertions
around a close-once-plus-drainStop. -
A toolchain capability table in
go.md, carrying no version numbers. Each rule states its
invariant; the mechanism is selected by ago docdetection command with a named fallback. Three
of the five version claims in the source material were wrong —T.Contextis Go 1.24 rather than
1.21,T.ArtifactDiris 1.26 rather than 1.24, andsynctest.Runwas the 1.24 experimental
spelling, replaced bysynctest.Testat GA in 1.25 and removed in 1.26. A rule naming
synctest.Runtoday produces code that does not compile. An exit code does not rot the way a
version number does. -
references/prose-standards.md— a nine-row catalogue of AI tells for agent-authored prose,
run as an editorial pass by/handoffand/release-managementand carried as one NIT row in
the Reviewer. It applies to docs, PR bodies and CHANGELOG entries, never to code comments, which
the stricter why-not-what rule already governs. It is not a gate: prose quality has no exit code. -
allowed-toolson the two genuinely read-only skills,checkcommentsandquality-gate,
both scoped to[Bash]since each shells out without mutating state.technical-analysisand
business-analysiswere considered and excluded — both write an HTML file, so annotating them
read-only would have broken their contracts. -
Two wiring checks in
validate-wiring.py: every skill named in the routing table resolves to
a real skill, and every skill description carries at least one trigger phrase. Both were verified
by breaking them, observing the failure, and restoring.
Changed
-
Trigger phrases now live in one place. They were stored twice — the routing table in
CLAUDE.mdand eachSKILL.mddescription — and all 23 pairs disagreed. Nine skills carried
zero phrases in their own description while the routing table listed 5 to 16 each, so
security-reviewwas reachable by "threat model", "auth bypass" and "CVE" only through a file
that skill discovery never reads. Descriptions are now the source of truth and the routing table
lists task to skill, which removes roughly 940 tokens from every session in every project. -
Sleep-based tests now block.
qa.mdstated "no real sleeps" inside a non-blocking test-quality
section. That clause moved into the blocking audit block as timing-coupled test, so one rule
owns the defect at one severity. This fails suites that pass today — a test whose correctness
depends on wall-clock duration proves the machine was fast enough, and that is the flakiness this
Harness keeps paying for. Probabilistic failure injection joins it as a blocking finding. -
Every PR opens as a draft and is promoted with
gh pr readyonce its review returns no
findings, on both the delivery path and the hotfix path. On the hotfix path promotion is gated on
the existing single review pass; that pass was not converted into a loop.
Fixed
-
write-a-skillrequired a tool that cannot run. It made SkillSpec a completion condition and
allowed skipping it only when "not installed". The binary here is installed and cannot execute —
an arm64 build on an Intel host. The condition now covers "cannot execute" and names the
fallback. -
Nine pointers to files that do not exist. Seven skills advertised
skill.spec.ymland
deps.tomlas a machine-checkable contract; two more referenced them from Rules bullets. No such
file exists in the repo, they are gitignored, and the generator cannot run. The sentence claiming
Claude never loads them was itself loaded on every invocation of those skills. -
write-a-skillenforced rules that most skills broke. The "Use when" prefix was required and
9 of 23 skills did not use it; trigger phrases were capped at 2–5 and 13 of 23 exceeded it, up to
10. Both rules were retired in favour of the Tier 1 token budget, which is now checkable.
rote's description also lost the imperative it duplicated from its own body.
Known limitations
-
The fallback named in
write-a-skillis shallower than SkillSpec.validate-wiring.pychecks
link resolution and trigger-phrase presence; it does not check behavior contracts, implicit
dependencies, or prose density. A skill authored after this release clears a weaker bar than the
skill file promises. -
business-analysisstill hard-codes Brazilian Portuguese output. Parameterising it was planned
and deliberately not shipped: it is a maintainer question about intended behaviour, and closing it
by picking a default is the author answering a question that was not theirs.
Full Changelog: v2.4.3...v2.5.0
v2.4.3 — Hook tests isolated from PATH; both install routes documented
The test bug, found by fixing something else
run_hook prepended the stub directory to the caller's PATH, leaving the real binaries reachable further down it. Every case asserting a tool is absent was therefore asserting something about the machine, not the hook. The suite was green for two releases — until jscpd was installed here, at which point nine assertions failed for reasons unrelated to the code under test.
Now scoped to <stubs>:/usr/bin:/bin. Verified both ways, which is the point: green with jscpd installed and with it hidden from PATH entirely; falsified by reverting to the caller's PATH, which reproduces the nine failures exactly.
Same defect class the suite's own header warns about — a gate passing for the wrong reason. It just happened to be in the tests rather than the hooks.
The double-loaded standards
install.sh imports ~/.claude/devkit/CLAUDE.md globally, so it applies everywhere. This repo also @-imported its own identical copy — ~6,560 tokens loaded twice per session, but only when working on the devkit itself. The repo file now points at the canonical path and tells an uninstalled contributor how to get it. No other repository was ever affected.
Both install routes, stated honestly
A plugin cannot write to .git/hooks/ and cannot ship a CLAUDE.md. Rather than pretend otherwise: the skills and agents restate inline the rules they depend on, so the plugin route works correctly standalone — verified, not assumed. What it does not carry is the repo-wide contract (Coding Discipline, Proportionality, Security Defaults, and the objectives that break ties), and the README now gives the three lines that add it. Both routes are supported; neither is going away.
Also
install.sh --dry-runprintednpm install -gjscpd, missing its space — a copy-pasteable command. The real install path was always correct.marketplace.jsonstill advertised an 11-agent pipeline without the Plan Reviewer.
Plugin versions: coding-pipeline 2.4.3
v2.4.2 — Reviewer audited against its own token rule
reviewer.md grew 2,894 → 5,972 tokens in v2.4.0 and loads on every review — the worst token regression of that release, and the one file not held to the rule the same release added to CLAUDE.md: an addition must earn its tokens against one of the seven objectives.
Now 5,614. 358 tokens removed, zero rules removed.
Verified identical before and after: every PE/RD/CD identifier · all six hard gates · all nine Security Deep-Dive sections · the scoring bands · the output block.
What went — all duplication or prose restating a rule stated elsewhere:
- Language-Specific Checks restated the specialist mandate and version policy carried by
references/languages/<language>.md, the file the Reviewer loads moments later. Now a pointer plus the two severities that file does not assign. - Design & Durability's closing paragraph restated the slop/overengineering table twelve lines above it.
- Reuse & Duplication restated the
jscpdcommand thatquality-gate-reference.mdowns. - Principal Engineer Standard and the Correctness procedure compressed, without losing a property, a step, or a severity.
What stayed on purpose — the three lines in the closing Rules: block repeating the cost test, the linter rule and the idiom rule. Terminal repetition of the governing constraint is load-bearing for adherence in a long agent prompt; trading that for ~90 tokens is the wrong side of quality-over-speed.
Measured context: per-story guidance load is ~27k tokens, QA + Reviewer being 45% of it — the confidence and validation the objectives rank first and second. That share was audited for duplication, not trimmed for size.
Plugin versions: coding-pipeline 2.4.2
v2.4.1 — Duplication scan excludes .git
Patch on v2.4.0.
Fixed — jscpd's ignore list omitted .git/, so git's own sample hooks were counted as duplication: noise in the pre-existing debt report, and a polluted denominator under every percentage the gate prints.
How it was found, and why the tests missed it — by running the gate end-to-end against real jscpd output rather than the hand-written report fixtures both suites use. test-dup-attribution.sh feeds the script a report the test file writes, and test-git-hooks.sh stubs jscpd entirely; together they prove the attribution logic and the hook's wiring, but they stub the invocation, so an ignore-list defect is structurally invisible to them. That limitation is now recorded in the suite header rather than left to be rediscovered, and the end-to-end check is the thing to repeat whenever the invocation changes.
Verified after the fix with real jscpd: a pre-existing clone passes and is reported as debt; a clone the delivery copy-pastes blocks and names both locations.
Plugin versions: coding-pipeline 2.4.1