Skip to content
AI CraftsmanSUPERPOWERS

Changelog

Version history for AI Craftsman Superpowers, from v1.0.0 to v4.10.3.

Last updated: Edit on GitHub

Latest version: v4.10.3

Update with: claude plugin update craftsman@ai-craftsman-superpowers

v4 is a clean break

v4.0.0 requires Claude Code 2.1.218 or later and drops backward compatibility with 3.x config. The 3.9.x line stays available and frozen for older installations. See the migration guide in the plugin repository.

v4.10.3 - 2026-09-14

A security patch and the tail of the whole-plugin review.

Fixed

  • never_ignorable held only on machines with PyYAML. On a machine without it (the macOS system python, the CI runners) the fallback reader hands the string true, the compiler compared it to the boolean, and SEC001, SEC002, SEC003 compiled as ignorable: an ignore marker silenced a hardcoded secret on the hook, the pipeline and the Hermes write gate alike. The compiler now reads the YAML boolean whichever reader produced it, and the registry test compiles the manifest both ways.
  • A capability key the engine does not read is refused at compile time, with the key named on stderr, instead of being skipped silently.
  • The ratchet is inert until a project opts in, and anchored on the file rather than on the shell’s directory: a hook fired from src/ of a marked project no longer skips it.
  • The dogfood test walks every shipped script and judges each finding through the rules engine; seven functions over the structure thresholds in the Go and Rust packs and the GitHub adapter are split into named helpers.

v4.10.2 - 2026-09-14

The rest of the whole-plugin review’s blocking findings, each seen red first.

Fixed

  • The Haiku verifier no longer grades itself. Any reply that was not the findings token was read as CLEAN and closed every earlier finding on the file as “fixed” with the file unchanged. Only the exact token is a clean verdict now; anything else is unavailable and closes nothing; a CLEAN closes a finding only when the file changed since the run that raised it.
  • A secret cannot be silenced with a marker, on any front-end. SEC001, SEC002, SEC003 are declared never_ignorable in the manifest; every marker reader asks the registry first.
  • An Edit is judged before it lands, like a Write, and a gate that cannot run refuses the write instead of letting it land with a warning.
  • Session state is one file per session. A session’s end no longer deletes another’s pending findings, and one project’s patterns no longer surface in another.
  • The pre-write gate judges through the packs. Its detectors were a fork (App hardcoded where the pack reads composer.json’s psr-4 root): an Acme\ project passed pre-write and was refused post-write. The would-be file is laid out under a mirror of the workspace and judged by the same validators post-write and CI run.
  • One global configuration layer (~/.claude/.craft-config.yml) for the hooks and CI alike, and none for the Hermes gates: a layer the same uid can write outside the gated turn must not shape a verdict.
  • Hermes: a gate file hidden from git is still the gate’s own, and a turn with no remote is scanned back to the root commit.

v4.10.1 - 2026-09-13

Added

  • A finding can be judged right or wrong, and each rule’s acceptance is reported (#44). /craftsman:metrics reports acceptance per rule and proposes a relaxation under the threshold. A verdict is about a finding, not an outcome, so it lives in its own verdicts table with two human writers: the reason spelled out in the suppression at the moment of the decision (craftsman-ignore: RULE (wrong: why) or (debt: why)), and metrics_record_verdict from the review after the fact. No path writes a verdict the developer did not spell out.
  • Hermes: the write-time promise, opt-in (#21). write_gate: on refuses a write_file or patch before it reaches disk on SEC001 (a hardcoded secret) and LAYER001 outside test paths. SEC002 and SEC003 stay at the conclusion gate: line-local regexes fire on the documented mitigations.

Fixed

  • pre-push-verify.sh ran on every Bash call. hooks.json carried the if filter beside matcher, where Claude Code ignores it. Moved onto the handler; the schema job refuses any other key at matcher level.
  • Documentation re-measured against the code. Agent count (12: 6 core plus 6 from the packs), ADR count (31), which skills the model may start (7 of 22), hook latency (measured, not “under 50ms”), analyser budgets (15s per file, 30s per project, not “under 2s”), pricing per model, the GitLab artifact shape, and a lesson that described a feature removed in ADR-0024.

v4.10.0 - 2026-09-13

Twenty-nine pull requests: the campaign that closed every open issue, then the fixes from a whole-plugin review by four reviewers crossed with the maintainer’s knowledge base on guardrails, evals and production feedback loops.

Fixed

  • Every Haiku verification used to end the real session. The headless claude -p verifier fired the plugin’s own SessionStart and SessionEnd hooks: the real session’s state was deleted on every verification, and 1460 of 1599 sessions in 30 days had no write at all. The correction loop was measuring its own verifier. Both hooks step aside under the guard the verifier already sets; proven on the real consumer.
  • agent_hooks: false never reached a hook. Claude Code exports an option as CLAUDE_PLUGIN_OPTION_<KEY> with the key uppercased; every reader read the lowercase spelling. The README’s “turn it off with agent_hooks: false” is true from this release.
  • An approved instinct was written where Claude Code never looks. .claude/skills/craftsman-learned/<rule>/ is one level below the depth a project skill is loaded from. approve writes to .claude/skills/learned-<rule>/ and refuses any other depth.
  • A scoping decision is no longer recorded as a fix. A directory .craft-rules.yml demoting a rule, or a baseline mark holding it, counted as fixed and three such files made a candidate for a learned skill. Recorded scoped and overridden now, which the instinct gate reads as rejection.
  • The pre-write gate resolves severity through the rules engine. The same file, rule and .craft-rules.yml gave “BLOCKED” before the write and nothing after it. One authority now; the advisory list it held is gone.
  • The gated party no longer reconfigures the gate. A Write to .craft-rules.yml, .craft-config.yml, .craftsman-baseline.json, .claude/settings.json or the plugin’s own code passed config-protection.sh. The gate’s own files go to the user’s permission prompt; Claude Code’s settings and the installed plugin are denied.
  • The instinct gate counted directories, not files. MIN_DISTINCT_FILES compared directory globs; 23 fixes under one glob made no candidate.

Added

  • An eval suite for the routing table (#48). evals/: eight cases over the six model-invocable skills, a counter-example where no skill may fire, a discrimination case, graded by tool_used and regex only. Run with scripts/run-evals.sh, never from tests/run-tests.sh: every case is a model call on your account.
  • Packs validate their files whatever the stack says (#35), the advisory default is declared once in the manifest (#37), one brace walk for every brace-delimited pack (#38), --changed-only in CI (#50), per-environment latency ceilings, the structural ratchet re-taken once.

v4.9.0 - 2026-08-27

Added

  • Bias detection language cascade. Bias patterns moved out of the hook into one data file per language, loaded by a registry. English is the single curated language and keeps its direct warning; twelve others sit at one same tier behind it, carrying recall-oriented lexeme lists whose hits are not warnings. The hook prints an adjudication note and the model already reading your prompt, holding the whole session, either surfaces the warning in your language or drops the note silently. No second model, no subprocess, no network call on the prompt path. A false positive there is invisible, which is what makes high recall affordable, and adding a language is two data files and zero code. Language tags follow BCP 47, so fr-CA or zh-Hant register like any other; before this, such a file registered nothing while the hook still exited 0.

  • Actionable verdicts. Measured on 18748 real violations: twelve rules fired 5624 times in 30 days and produced zero corrections, in either direction. Two causes, both fixed. A rule now names what it found, because the rule that named an identifier was acted on 167 times while the one that named nothing was acted on never. And both output paths now offer scoping before silencing: the blocking path had named suppression as the only way out, so a rule wrong for a whole directory was suppressed once per file instead of scoped once, and the advisory path carried no action at all.

  • scoped and open outcomes in the metrics. Scoping a rule was indistinguishable from giving up on it, and a verdict that reached the end of a session with no outcome was invisible. Both are now recorded, which is what makes the two fixes above measurable rather than merely plausible.

  • Verifying the instrument, in the knowledge bundle. Five instrument failures were observed in one session and none was a defect in the code under test: a check that read a comment instead of the emitted message, a pattern that matched inside the corrected name and reported the fix as the defect, a fixture that never triggered the rule it tested, an all-time aggregate that described a problem solved a month earlier, and a verification whose output was piped away unread. Code is exercised constantly and fails loudly; an instrument is exercised once, silently, and its failure looks like success.

v4.8.1 - 2026-08-11

Changed

  • tests/core/test-config.sh split into 21 section functions. The last whole-file span in the top three structural offenders: complexity 102 to 10, longest span 505 to 30 lines, 90 assertions before and after. Two oversized intermediate functions were blocked during the campaign and both were re-split instead of suppressed.

v4.8.0 - 2026-08-11

Changed

  • Structural debt campaign, first production run of /craftsman:loop. The two worst production offenders in the ratchet baseline were extracted under their marks with behaviour intact (full suite green at every iteration): hooks/session-metrics.sh worst-span complexity 37 to 8 and longest span 131 to 16 lines (duration, write counter, violation counter and summary builder each became a function); hooks/lib/dispatch-context.sh complexity 28 to 11 and longest span 97 to 27 (one emitter function per context section, early returns instead of nesting). The file_lines rises (131 to 149, 97 to 110) are the function boilerplate paid for it and are recorded in the baseline with that reason; every other mark tightened one-way.

v4.7.0 - 2026-08-11

Added

  • /craftsman:loop, a bounded verification loop. The repeat layer on top of the existing gates, with a stated bound rather than an open-ended retry.
  • tests/core/test-gate-independence.sh. Auto mode becomes the default, and the test asserts each gate still decides on its own.
  • A context footprint guide. What the plugin injects per session, measured rather than estimated.

Changed

  • The advisory Haiku layer respects the effort dial, so a low-effort turn no longer pays for a review it did not ask for.
  • /craftsman:team offers the native Workflow tool explicitly, and /craftsman:workflow documents how it maps onto the native /goal.
  • /craftsman:challenge states its position against the native reviewers instead of leaving the overlap implicit.
  • /craftsman:metrics publication is explicit, never a side effect.
  • Three skills removed: agent-design, mlops and rag. The plugin ships 19 skills.

v4.6.4 - 2026-08-10

Fixed

  • /craftsman:challenge returned nothing at all, one run in two. The skill forked into an agent capped at 20 turns. When the cap lands on a tool call the loop stops there and returns no text, and Claude Code substitutes the literal string Command completed for the missing result. No error, no partial, no retry: 23 of the agent’s first 38 recorded runs ended that way. The review now runs in the main session and fans out to reviewer subagents when the scope is large.
  • The review could not see what it was reviewing. A forked skill carries neither the conversation nor the attachments. A review invoked with seven screenshots received seven [Image #14] tokens and zero images.
  • The architect agent reviewed a tree in which the diff did not exist. It declared an isolated worktree, which is a clean checkout of a commit, so the uncommitted changes its injected git diff HEAD pointed at were absent from it.

Added

  • Every agent that caps its turns now carries a delivery contract: emit the deliverable as soon as the evidence justifies it, reserve the last third of the budget for writing, name what was not covered, never end on a tool call. The cap was never the whole defect: an agent that keeps no budget for writing fails at any cap.

v4.6.3 - 2026-08-09

Fixed

  • The deptrac adapter had never produced a single verdict. It called a formatter that exists in no version of deptrac. The call failed, the output was swallowed by 2>/dev/null and || true, and DEPTRAC001 was never emitted once. Every layer violation this plugin ever reported came from the import regex. Nothing caught it because no test asserted that the analyser produced output, only that the code path ran.
  • A project could not configure the severity of a layer verdict. deptrac findings arrived under a code no .craft-config.yml addressed, so block, warn and ignore all produced the same outcome.

v4.6.2 - 2026-08-09

Fixed

  • /craftsman:team gated native teams on a tool Claude Code had removed, so every session silently degraded to parallel subagent dispatch.

Added

  • Level precedence between validation levels. A rule a static analyser owns is deferred, never dropped: if the analyser times out, crashes, or is configured to ignore the rule, the regex finding is re-emitted. No verdict is not a clean verdict.

v4.6.0 - 2026-08-08

Added

  • Packs own the rules they enforce, instead of a central export holding every rule for every stack.

v4.5.0 - 2026-08-08

Added

  • Initialising a ratchet baseline requires a written reason, and records it. A scoped exemption with no stated cause is how a ratchet quietly stops ratcheting.

Fixed

  • The structural metrics measured the gap between functions, not the functions.

v4.4.0 - 2026-08-08

Changed

  • Packs declare the languages they cover, and the engine holds no list of its own. Breaking for pack authors.

Fixed

  • The python and bash packs never ran in CI. The scan walked paths neither of them lives in.
  • One PHP file silenced the empty-gate guard for every other language.

v4.3.0 - 2026-07-29

Fixed

  • The orchestrator told the model to run skills the model cannot run.
  • The subagent quality gate validated nothing. Its header claimed it validated; it did not.
  • A review could silently run a model tier below what the docs promise.

Every version, in full

The complete history, including the patch releases summarised here, is in CHANGELOG.md in the plugin repository.

v4.2.0 - 2026-07-28

An audit release. Every finding below was reproduced before it was fixed, and each carries a test that fails when the fix is removed. The recurring shape is one defect wearing different clothes: a control that reports success when it did not run, and a measurement that reports a number the code does not have.

Security

  • A cloned repository could write anywhere the developer could. ratchet.py wrote its baseline with write_text, which follows a symlink, so a repo shipping that path as a link to ~/.claude/settings.json had the target overwritten on the first edit. Writes now go through a sibling temp file and land with os.replace, which acts on the link and never on its target.
  • A cloned repository could switch the gates off. hooks.disabled resolved from the project file first, so a clone could open its first session with every gate silent. A repository may tune what the gates check, never whether they run.
  • A psr-4 key could disarm the layer rules. _layer_ns_regex escaped backslashes only, so a root such as A(pp\ made every layer grep exit 2, which reads as “not this layer”. LAYER001 to LAYER003 stopped firing repository-wide, in the hook and in CI.
  • A file name could address the reviewer. Names from git diff and tool_input were spliced verbatim into the Haiku review prompts. Names outside a plain-path charset are dropped, and the drop is reported.
  • A learned skill carried unsanitised text into the model’s context. A newline in pattern_summary or file_pattern opened a second YAML frontmatter block in the generated skill. Both are collapsed, capped and stripped of the fence character, and the skills destination is confined to the project or ~/.claude.

Fixed

  • CI reported a pass on a pipeline that inspected nothing. The default scan path was src/, so a Laravel app/, a monorepo packages/ or a Next.js app/ matched nothing and the run exited 0 with files_scanned: 0. Every common source root is scanned now, discovery is counted separately from scanning, and an empty discovery fails loudly.
  • Three blocking rules reported findings the code did not have. SH002 and WARN-SH001 counted braces without knowing which were shell, so a 14 line function holding an embedded python snippet was reported as 128. PY001 grepped raw lines, so a docstring beginning with an English article blocked writes on prose. SH001 inspected the first 20 lines only. All four measure from a proper scanner now.
  • The exported doctrine covered 15 of 38 rules and described three of them wrong. PHP003 was documented as “private constructor plus factory” while it enforces “no public setter”; PHP004 as “no setters” while it enforces “no new DateTime()”; TS002 as “readonly by default” while it enforces “no default export”. A teammate on Codex read one rule and was blocked by another.
  • The test suite trained the learning loop on its own fixtures. tests/run-tests.sh set no CLAUDE_PLUGIN_DATA, so four months of runs recorded their fixtures as production violations: 3704 of 15588 violations sat on a path this repository does not have.
  • Session counters were decorrelated from reality. SessionEnd re-queried the violations table over a window the length of the session, which counts every other session’s rows: 236 sessions in one day reported 16236 warnings against 1353 actually recorded.
  • Level 2 and 3 could not run and said they were clean. Every analyser was capped at 2 seconds, below the cold start of all of them, and || true flattened the timeout into success.
  • Rules vanished in silence without python3. Six checks shell out to it and each returned quietly, so the packs reported every file clean on a machine that has none. sqlite3 gets the same treatment in the metrics layer.
  • Whole classes of file were never validated. post-write-check allow-listed the characters a path may contain, so every Next.js App Router dynamic route, every route group and any accented path went unchecked. The rule is inverted to refuse only what is dangerous.
  • Bitbucket published a green PASSED on an unreadable report. The verdict now travels in the result field and its reason in the free-form details line.
  • metrics_project_hash hashed $PWD, filing one repository under a different project for every subdirectory worked from, and metrics_file_pattern recorded absolute paths, including the developer’s home directory.

Added

  • adapters/, a third front-end over the same core. hooks/ serves Claude Code, ci/craftsman-ci.sh serves pipelines, and adapters/<host>/ serves other agent runtimes. The first is adapters/hermes/: a pre_verify hook that refuses a conclusion rather than a write, because blocking a write assumes somebody can break the loop it creates, and an autonomous agent has nobody. It derives its scope from git rather than from the agent’s self-report.
  • Test paths degrade the rules whose premise is production code. LOC001, NEST001, PARAM001, GOD001, CTRL001, SEC001 and SEC002 become warnings under tests/, spec/, __tests__/, __mocks__/, fixtures/ and factories/. A long setup and a credential in a fixture are the normal shape of a test, and blocking on them is what teaches a developer to reach for craftsman-ignore.
  • A source column on violations and corrections, so the next contamination is a DELETE rather than an archaeology exercise.

v4.1.2 - 2026-07-27

CI duration, which on this project is CI cost.

Changed

  • Adaptive polling in the portable timeout. The fallback slept a full second per call while almost every call finishes in milliseconds, adding 163s to the macOS job. It now polls at 50ms, backing off to 250ms after a second and 1s after ten. Measured over 50 fast calls: 972ms per call before, 64ms after.
  • One timeout implementation instead of three. hooks/lib/portable-timeout.sh is the single source; the static-analysis dispatcher, the test helpers and the test runner all source it.
  • The workflow cancels superseded runs. Without a concurrency block, pushing twice ran two full matrices for one answer that mattered.

Added

  • A Python floor job. The test matrix used 3.12 on both runners, so it could not see a module that only parses on 3.10+. A separate job imports every hook library under 3.9.
  • The runtime floor is stated in both READMEs: Python 3.9, no GNU coreutils required.

v4.1.1 - 2026-07-27

Every failure here was a “works on my machine” dependency the repository had been carrying unnoticed.

Fixed

  • Level 2 and Level 3 static analysis never ran on a stock macOS. All five analyser invocations were wrapped in timeout, which comes from GNU coreutils and is not installed by default on macOS. The call failed with 127, the || true swallowed it, and the plugin reported a clean gate having run nothing. sa_timeout now uses timeout or gtimeout when present and falls back to a background job with a watchdog.
  • The instinct pipeline was dead on a stock macOS. hooks/lib/instincts.py annotated a parameter with syntax Python evaluates at runtime from 3.10, and /usr/bin/python3 on a Mac without homebrew is 3.9. Fixed with from __future__ import annotations.
  • sed -i '' is BSD syntax and GNU sed reads the empty string as the script. Fixed in the pack validator test, which failed on Linux, and in bump-version.sh, which would have silently skipped a version bump for any contributor on Linux.

v4.1.0 - 2026-07-27

Security fixes, rule calibration, and twenty test suites the runner never called.

Security

  • The CI gate no longer fails open on a malformed report. It parsed the report with stderr discarded, so a report that was not valid JSON produced an empty summary and exit 0. It now fails closed.
  • Command injection through a channel number closed. Config values landed in an arithmetic expansion where bash evaluates an array subscript as a command. Refused at the config boundary and again at each sink.
  • Grep flag injection closed at three sites: a pattern beginning with - was read as an option.
  • secrets-scan fails closed. It reported “no secrets found” for every condition that makes a scan produce nothing. It now proves it can enumerate tracked files, read their content and read history before any empty result counts as clean.
  • Six credential shapes added to the scan, and every .env suffix rather than only .local and .production.
  • hotspot_analysis.py bounded. A 400MB file with no newlines took 952MB of RSS. It now shares the write-time gate’s 2MB cap.

Changed

  • TS002, TS003 and PHP003 default to advisory. Each has legitimate exceptions a regex cannot see, and blocking a write on those only teaches suppression.
  • PHP002 skips Doctrine entities. A proxy extends the entity, so a final entity breaks lazy loading: the rule was asking Symfony projects to break their own persistence layer.
  • TS002 skips files a framework resolves by default export (page, layout, route, middleware, and others), and both TS rules now take a line-level craftsman-ignore.
  • The layer rules read the project’s root namespace from composer.json. They matched App\Domain literally, so every project that renamed its root namespace passed all three layer rules by construction.

Fixed

  • The CI quality gate no longer hangs. Severity resolution walked from the file’s directory up to the project root, but both stop conditions are absolute paths and CI is handed relative ones.
  • CI agrees with the hook on ignore, and resolves severity per file so a directory-level .craft-rules.yml applies in the pipeline as it does in the hooks.
  • consolidate-metrics.sh reports its failures instead of reading a locked source as “0 rows to merge”.
  • pack_sync_symlinks only removes what a pack put there.

Testing

  • Twenty test suites the runner never called are now wired in, including the entire hostile-repository security suite. The suite reported 213 passing while a third of the files on disk sat unexecuted. test-runner-integrity.sh now fails when a test function is defined and not called.
  • A failing subtest says why. All 26 wrappers used to discard their output.
  • Guard tests can no longer pass against deleted code. Every absence assertion is gated on a positive control only a live tool can satisfy.

v4.0.1 - 2026-07-27

Corrects two settings that did not do what the repository believed.

Added

  • Per-task model tiering, actually implemented. Every skill declares the cheapest model that can do its job (haiku for mechanical work, sonnet for bounded pattern application, opus for judgment spanning files) alongside its effort level. The tiering had been documented since v1 but never implemented: no skill declared a model, so every skill ran on whatever the session happened to be set to. Tiers are aliases rather than pinned model ids, so they follow model releases and a whole tier can be remapped with ANTHROPIC_DEFAULT_*_MODEL.

Fixed

  • effort used values Claude Code does not recognise. Eleven of twenty-one skills declared quick or heavy, a project convention that predates the key.
  • Skills reference was missing healthcheck, legacy and workflow. The table is now generated from the frontmatter it documents.
  • Hooks reference documented 8 of the 13 wired events, omitting the TaskCompleted evidence gate.
  • Installation and advanced guides still walked users through the knowledge-rag MCP server, removed in 4.0.0.
  • CI validators required frontmatter keys Claude Code treats as optional, and read keys from the whole file so a YAML sample inside a skill body was mistaken for a declared field.

v4.0.0 - 2026-07-26

A clean break to a native-first, self-learning, security-hardened plugin. Requires Claude Code 2.1.218 or later. Rationale: ADRs 0016 to 0027.

Added

  • Structural ratchet. A committed .craftsman-baseline.json holds each file’s structural high-water mark (approximated complexity, file lines, longest function, import fan-out, suppression count). A file you touch may improve or stay equal, never regress. The mark tightens automatically on a green pass and only loosens through a documented craftsman-ignore, itself counted and ratcheted. The hook and craftsman-ci run the identical check, and CI never writes the baseline. Untouched files and relaxed directories are never evaluated, so legacy is not punished for debt it already had. Ships advisory: set RATCHET001: block to make it a hard gate.
  • Correction learning closes the loop. Recurring fixed corrections (3 or more across 3 or more files) become candidate instincts; /craftsman:metrics surfaces them for human review; approval generates a learned skill with provenance. Instincts stay project-scoped until the same rule is approved in 2 or more projects. Promotion is never automatic.
  • Adversarial design panel. Three headless contradictors (YAGNI, invariants and aggregate boundaries, feasibility) attack the design during /craftsman:design phase 2, before any code exists. Every objection must land in a retained or dismissed table.
  • Persistence craft. New knowledge pillar plus rules verified in hooks and CI: LAYER004 (raw SQL or a database client inside Domain), DB001 (SELECT *), DB002 (migration without down()), DB003 (query inside a loop).
  • Security rules SEC001 to SEC003: hardcoded secrets, dynamic eval, and SQL built by concatenation, with doctrine routed automatically when one blocks.
  • Knowledge as an OKF bundle. Every concept carries Open Knowledge Format v0.2 frontmatter, and a deterministic lookup routes a rule or tag to the concepts explaining it. Zero embeddings, zero index, zero external service.
  • Level 1.5 semantic validation. .lsp.json activates a language server only when the binary is already installed on the machine.
  • Deterministic verification loop. A failing test run revokes verification evidence and wakes the session on regression; a TaskCompleted gate requires evidence before a task can be marked complete.
  • Situational onboarding and guided mode. Project init observes the repository, then asks at most four plain-language questions. With guided: true, every block explains its doctrine.
  • Living legacy audit. LEGACY-AUDIT.md is committed and diffed between runs, with a mandatory “looks bad but is actually fine” section. Nothing is ever installed for you.
  • Outcome contracts. Every skill states its outcome, its done-when condition, and the evidence that proves it. The validator enforces all three.
  • Cross-harness doctrine export. craftsman-ci export renders the active rules as AGENTS.md, .cursor/rules/craftsman.mdc and .github/copilot-instructions.md.
  • Local dashboard. /craftsman:metrics --dashboard aggregates every tracked repository into a self-contained page served on localhost.
  • Context budgets and kill switches. Every injection is capped and every hook individually disableable.

Changed

  • All workflows are skills. commands/*.md became skills/<name>/SKILL.md. User invocations are unchanged: /craftsman:design still works exactly as before.
  • Semantic verification is headless. DDD verification moved from Stop (where it was dead) to PostToolUse and runs in a Haiku subprocess. Zero main-context cost, and agent_hooks: false still disables everything.

Security

Hardened against a hostile repository: opening or editing one must not execute its code. Each fix has a test in tests/core/test-hostile-repo.sh that reproduces the attack and asserts it fails.

  • Level 2 static analysis is off by default (breaking). The gate resolved and executed vendor/bin/phpstan and node_modules/.bin/eslint from the working directory, so a shell script planted at that path in a cloned repository ran arbitrary code on the first PHP edit. Running a project’s analysers means running its code, so it is now consent: set trust_project_tools: true in your own global config. A repository cannot grant it to itself.
  • External packs are declared by the machine owner only. Their validators are sourced as shell code, so reading that path from a project config meant opening a cloned repository executed its code at session start.
  • No Python source splicing in the GitLab adapter: an attacker-chosen filename reached the source text of a python3 -c call.
  • Rule ids are constrained. They are YAML keys from repository-controlled config and were used raw as filenames.
  • Dashboard output is escaped and the server answers for exactly one file.
  • Symlinks are refused. Git tracks symlinks as real entries, so src/Thing.php pointing at ~/.ssh/id_rsa is a legal commit and the audit followed it.
  • Reads are bounded. Measuring a 94MB file cost 506MB of memory, and a size cap alone does not help because a symlink to /dev/zero reports size 0.
  • Verification verdicts are parsed by shape before reaching the session. The headless verifiers read files the plugin did not write, and forwarding their reply verbatim is an indirect prompt-injection path.
  • Shipped CI template hardened: actions pinned to verified commit SHAs, least-privilege permissions, anchored paths.

Removed

  • commands/ flat command files, output-styles/, and the v3 agent hook wrappers.
  • The knowledge-rag MCP server, its skill, the Ollama dependency, and 115MB of dependencies. Superseded by the OKF bundle.
  • Support for Claude Code below 2.1.218.

v3.9.0 - 2026-07-14

Added

  • Global config fallback. ~/.claude/.craft-config.yml written by /craftsman:setup is now actually read by hooks. Resolution order: project config, then plugin option env vars, then the global file, then hardcoded defaults.

Fixed

  • CI executable-bit check no longer fails on sourced libraries.
  • bump-version.sh exits 1 when a tracked file matches neither the old nor the new version, instead of printing a soft warning that let a file silently drift two releases behind.

v3.8.0 - 2026-07-14

Added

  • Config protection hook. Blocks writes to single-purpose linter and architecture config files, so an agent cannot silently loosen a rule instead of fixing the flagged code. Multi-purpose files (pyproject.toml, package.json) are intentionally excluded.
  • Hook profiles. Session-level opt-out of secondary and costed hooks. The core quality gate, bias detection and session bookkeeping deliberately do not support it.
  • Security invariant tests. A sandbox and witness-marker suite proving the protection hooks never execute injected code, never touch files outside their contract, and fail open on malformed stdin.
  • Prompt injection defense baseline: external content relayed by hooks is data, never instructions.
  • French README, FAQ, migration guide, and troubleshooting guide.

Changed

  • CI hardening: all actions pinned by commit SHA, least-privilege permissions, dynamic script discovery, and the test suite running on an Ubuntu plus macOS matrix.

v3.7.0 - 2026-07-06

Added

  • /craftsman:legacy. Four modes for regaining control of an inherited codebase: audit (rank hotspots, produce LEGACY-AUDIT.md), cover (characterization net before touching anything), untangle (break dependencies), migrate (strangler fig). Consumes existing analysis-tool output via --from instead of recomputing a weaker signal.
  • legacy-surgeon agent and the legacy-takeover team template.
  • Zero-dependency hotspot ranking (churn times complexity), as a fallback for teams with no external analysis tool, not a competitor to one.
  • Legacy and refactoring knowledge pillars: characterization testing, strangler fig, Mikado method, code smells, communicating technical debt.

v2.6.0 - 2026-03-29

Pack ecosystem expansion.

Added

  • Pack validation script validating pack structure, manifest and hooks before publishing.
  • External pack support loading community packs from arbitrary paths.
  • Pack creation guide with examples.
  • Pack skeletons for Go, Rust and Python, ready to fork.
  • /craftsman:scaffold pack generates a pack skeleton interactively.

v2.5.0 - 2026-03-29

Knowledge-RAG MCP server migration. (This subsystem was later removed in v4.0.0, replaced by the OKF knowledge bundle.)

Added

  • Knowledge-RAG MCP server moved to a standalone directory, with stdio and HTTP transport.
  • /craftsman:scaffold api-resource for API Platform 4 resources.
  • Pack-specific test suites, and CI pack-loader integration.

v2.4.0 - 2026-03-29

Core plus pack architecture.

Added

  • Pack loader reading pack manifests and registering agents, commands and rules.
  • API craftsman agent for API Platform 4 resources.
  • Unified scaffold command replacing the separate entity, usecase, component and hook commands.

v2.3.0 - 2026-03-29

Distribution optimization.

Added

  • Distribution ignore list, bringing the plugin under 1 MB.
  • Startup dependency check for Python 3, jq and SQLite.
  • Agent hooks opt-out.

Fixed

  • Knowledge base is lazy-loaded instead of read at startup.

v2.2.0 - 2026-03-29

Security and quality.

Security

  • All database writes use parameterized queries.
  • Hook entries in .claude/settings.json are schema-validated at startup.

Added

  • Atomic commit enforcement: the Stop hook warns above 15 staged files.
  • Monorepo sampling: above 100 changed files, a representative sample per directory is validated instead of every file.

v2.1.0 - 2026-03-29

Rules engine and CI adapters.

Added

  • Custom rule engine with 3-level inheritance (global, project, directory).
  • Short-form rules and long-form custom rules with regex and per-language targeting.
  • CI adapter system for 4 providers: GitHub Actions, GitLab CI, Bitbucket Pipelines, Jenkins.
  • /craftsman:ci to export CI config and check status.
  • Circuit breaker with 3 states, protecting the plugin’s own external service calls.
  • Pack template variants.

v2.0.0 - 2026-03-28

Teams and onboarding.

Added

  • Teams system with built-in templates for code review, feature implementation and security audit.
  • Session onboarding with config summary and cost estimate.
  • Pre-push verification on the Stop hook.

v1.5.0 - 2026-03-28

Agent fleet expansion.

Added

  • 5 specialized core agents: architect, doc-writer, security-pentester, ui-ux-director, team-lead.
  • Parallel agent execution via /craftsman:parallel.
  • Pack agents: backend-craftsman (Symfony), frontend-craftsman (React), ai-engineer (AI/ML).

v1.4.0 - 2026-03-28

Sentry integration.

Added

  • Sentry context fetching with a channel lifecycle and automatic cleanup.

v1.3.0 - 2026-03-28

Semantic intelligence and correction learning.

Added

  • Agent hooks analyzing code changes for DDD and Clean Architecture compliance.
  • Correction learning system: SQLite tracks when Claude corrects a violation.
  • Metrics database, the foundation for 7-day and 30-day trend analysis.

v1.2.0 - 2026-03-28

Validation levels and metrics.

Added

  • Multi-level code validation: regex (under 50ms), static analysis, architecture.
  • Blocking hooks: the write is refused until the violation is fixed.
  • Pre-write validation, so the check runs before the write rather than after.
  • /craftsman:metrics quality dashboard.
  • craftsman-ignore inline suppression syntax.

v1.1.1 - 2025-02-06

Added

  • /craftsman:setup implementation, with a DISC mini-assessment in the wizard.

v1.1.0 - 2025-02-05

Fixed

  • Version synchronization between manifest files.

v1.0.0 - 2025-02-04

Initial release.

Added

  • 20 commands: 10 core, 2 PHP, 2 TypeScript, 4 AI/ML, 1 CI, 1 utility.
  • 5 specialized agents.
  • Hooks system: PreToolUse, PostToolUse and Stop validation pipeline.
  • Knowledge base covering DDD, Clean Architecture, TDD and framework specifics.
  • Optional Knowledge-RAG MCP server via Ollama for vector search.
  • 3 built-in packs: symfony, react, ai-ml.