Releases: jellologic/claude-code-muse
Release list
v1.4.0 — supervision enforced, measured end to end
Work since 1.3.0 (epic #49): supervision is enforced rather than described, the
credential scan covers what the worker actually receives, configuration refuses bad
values instead of silently defaulting, and prose counts are held against the code by a
new offline check.
Follow-ups (epic #58)
- Interruption and scanning (Refs #52). A signal after the worker returned but
before the round was saved un-counted the round and left a stale in-flight marker; an
ordinary error was recorded as an interruption; a slowgit ls-filescrashed task and
fleet; read-onlymuse-asknever scanned for credentials. Each is fixed and
reproduced offline, and a scan that cannot list files now refuses. - Harvest excludes follow git's glob rules (Refs #53):
*and?stay inside one
path segment, so--exclude 'a/*.py'no longer dropsa/b/c.py. - The supervisor's documented commands pass its own guard (Refs #54), the block
reason prints a runnable finish command, and a recorded check is allowed only inside
the owning task's worktree. - Ten more mutants killed (Refs #55) and tests that could not fail now can
(Refs #56).mutate.shderives its per-mutant timeout from a timed control run and
drops to one job under load, so a busy host no longer reports false timeouts. model:frontmatter measured per permission mode (Refs #57): it takes effect in
default, acceptEdits and bypassPermissions, and auto and plan keep the session model.- The eval judge is replayed byte-for-byte (Refs #50) and the README records
measured vote splits instead of the best run. On a macOS host the eval sandbox blocks
the Command Line Tools, so cases that need git or python3 are measured on Linux
(Refs #59).
Added
- A PreToolUse guard denies a supervisor's writes (Refs #43). Omitting
Writeand
Editfromallowed-toolsonly left them prompted, and the skill pre-approved broad
Bashgrants — so the supervisor keptBashand a hook (hooks/supervisor_guard.py,
matcherBash|Write|Edit|NotebookEdit) now denies its Write/Edit/NotebookEdit and any
Bash beyond muse shims, read-only git, readers and the recorded check. The skill
pre-approves only read-only status/doctor shims and readers. - A SubagentStop block plus a PostToolUse census for the central claim (Refs #40).
SessionEnd output is discarded, so leftover worktrees were reported to nobody, and the
stop check never matched the supervisor's agent type. SubagentStop now matches
^muse:muse-supervisor$and blocks (at most twice per task) a supervisor that stops
with no verdict, PostToolUse onAgenttells the orchestrator where the on-disk
artifacts disagree with the summary, SessionEnd is removed, and the SessionStart
preflight names recorded muse/ and fleet/ worktrees still open. - Fleet supervisors run as muse-supervisor, and unverified tasks are counted from disk
(Refs #44). The workflow spawned supervisors without the agent type, trusted each
supervisor's self-reported verified flag, and interpolated briefs into double-quoted
shell; the census now reads eachtask.json, and briefs and checks travel via files. - Shims on PATH with narrow grants (Refs #42).
bin/shipsmuse-ask,
muse-cleanup,muse-doctor,muse-fleet,muse-model,muse-statusand
muse-task; docs and grants name them bare. - An offline stub round trip against a moving base branch (Refs #32), so diffing
against a ref name can no longer silently stand in for the pinned sha. scripts/mutate.shplants each known bug and fails when a must-kill one survives
(Refs #32).- A frontmatter checker with a probe self-test, and a pinned CI toolchain
(Refs #34).claude plugin validate --strictcatches YAML parse errors only
(measured on 2.1.280), soscripts/check_frontmatter.pyholds keys and value types;
CI installs the CLI atMIN_CLAUDE_VERSION, pins actions by SHA, and runs shellcheck
at severity=error. - A doc-claims check holds prose counts against the code (Refs #47).
tests/test_doc_claims.shfails when a command, shim, auto-triggering surface, flag
or hook event is added without updating the prose — each with a probe proving the
failure names the planted defect. - A monitor and a status line for supervised tasks (Refs #48).
muse-taskand
muse-fleetappend round, verify and verdict events; a plugin monitor streams each as
one notification line, andsettings.jsonsets asubagentStatusLineshowing the
task, round N/M and the last check.claude plugin detailsdoes not inventory monitors
or settings on 2.1.280, sotests/claude_validate_monitors.shis the proof they load. - The evals run for real (Refs #33). Every case is a
case.yamlwhose scaffold builds
its fixture repo and puts a stub muse on PATH, so nothing leaves the machine; cases get
the tools their behaviour needs (Workflow is gated on 2.1.280) andevals/README.md
records measured scores. All nine triggering graders pass; one behaviour judge
(trust-the-self-report) is still inconsistent.
Changed
- userConfig refuses bad values and reaches every driver (Refs #41). Unparseable
values were silently replaced by defaults, and some keys never reached fleet, ask or
the workflow. Every driver now refuses before spawning, all five keys reach task,
fleet, ask and the supervised workflow as flags, worktree roots resolve against the
repo and refuse one inside it, and doctor reports each value with its source. Each
script resolves flag first, thenCLAUDE_PLUGIN_OPTION_<KEY>, then the default, and
refuses a set-but-invalid value rather than falling back. - The credential scan covers exactly what the worker receives (Refs #39). It missed
dotfiles, used narrow patterns, and scanned a different directory than the worker
started in; one scan now coversgit ls-filesplus seeded and linked paths and the
gitignored files of the worker's start directory, and all three drivers honour it. - The token diet (Refs #47). The supervisor agent's description carried three
<example>blocks (~600 always-on tokens) and invited auto-triggering, which the docs
never intended. It is now a two-line description; the skill description is trimmed to
about half with every trigger cue and exclusion kept. Always-on falls from ~1,202 to
~625 tokens, against the 750 ceiling (the skill description regained the trigger cues
two positive eval cases had stopped firing on). - The Windows Git Bash leg is blocking (Refs #32). It runs the same free offline
suite; the tests stub their host dependencies instead of asserting the runner's
health, strip CR from Python output, resolve executables throughshutil.which, and
kill the whole tree on timeout.
Fixed
- Worktree safety: cleanup, harvest, resolution, collisions (Refs #36, Refs #35,
Refs #45, Refs #46). Cleanup could delete the repo, human worktrees and unharvested
work; harvest dropped tracked build files and binaries and mishandled nested
excludes;--outand the repo resolved against the cwd instead of the owning
repository; fleet never checked branch or patch collisions. Each now refuses or
resolves correctly, with an offline reproduction ending in the data intact. - Robustness: bytes, signals and round-in-flight (Refs #37, Refs #38). Non-UTF-8
worker or check output raised after the round ran but before it was recorded, so the
round never counted; a signal left the worker running under a reaped worktree; a
second round could start on the same task. Output is bytes-safe with the round
recorded before fingerprinting, signals kill the process tree, and a marker answers
round_in_flightwhile the worker lives. - Test and CI integrity: count guard, mutate.sh and the frontmatter checker refuse
what they let through (Refs #32). A misspelled mutate id ran only the control and
exited 0, totals were hard-coded, a hung mutant had no timeout and a crash counted as
killed; the count guard counted skips; the stamp guard grepped instead of parsing.
All eighteen known mutants are now killed andMUST_KILLholds every one. - An unset userConfig key no longer blocks delegation (Refs #41). Claude Code
substitutes${user_config.KEY}only for keys the user set and leaves the rest
literal; the prose double-quoted them, so the shell failed with "bad substitution"
before any script ran. Placeholders are single-quoted, and a literal placeholder for a
flag's own key counts as not given, so the default applies. Found by a real
no-config end-to-end delegation, which now completes.
Corrected
Claims in 1.3.0 that were false, corrected here rather than silently edited there:
- The SessionEnd hook reported open worktrees to nobody — SessionEnd output is
discarded — and is removed in favour of the SessionStart leftover report (Refs #40). - SubagentStop plain output never reached the orchestrator; the hook now blocks, and
the PostToolUse census carries the report (Refs #40). - The 1.3.0 note that the validator rejects
optionson userConfig does not hold on
2.1.280, which accepts it;plugin.jsonnow usesoptionsondefault_effort
(Refs #41). model: haikuon the reporting commands (Refs #29, Refs #57) is now measured on
2.1.280: headless runs with--model sonnetserve/muse:statusfrom
claude-haiku-4-5-20251001 in default permission mode, and amodel: haiku
skill control is likewise served by claude-haiku-4-5-20251001 in acceptEdits
and bypassPermissions modes, while auto and plan keep the session model with
the debug warning that names skills and commands together as one mechanism.
The frontmatter stays, and the runs are recorded in references/field-notes.md.SKILL.mdsaid six commands and lists seven; the Running-it table and the details
section pointed atreferences/workflow.mdas the workflow script, which that file
...
v1.3.0 — the verification guarantee, enforced
The plugin's central claim is now enforced in code rather than stated in prose.
completedmeans the worker stopped.acceptmeans a supervisor ran a check and the final one passed.
That sentence appeared in the README, the skill, the supervisor agent and the workflow reference. An adversarial review reproduced a task recorded as accept / verified whose acceptance check asserted the opposite of what the patch contained, and found the guarantee enforced nowhere. This release closes that gap and the twenty-one others the review and its follow-ups found.
The gate
finish --verdict accept now refuses unless three separate conditions hold — a check ran, the final one passed, and it ran against the patch being harvested. The refusal names which one failed and exits non-zero, and it returns before the cleanup branch, so a refusal never reaps the work the supervisor was just told to go verify.
--accept-unverified "<reason>" records the one legitimate exception — a correct patch that makes its check go red, a strict xfail being the usual shape — instead of hiding it. /muse:status prints the reason on the task's row.
The binding is a fingerprint of the patch, taken after the acceptance command. Both were corrections to a first attempt that hashed the whole worktree before the command: that version refused every check that builds, formats or generates, which is most of them.
The claim we retired
The code said the supervisor's toolset made hand-editing impossible. It does not — the supervisor has Bash, a shell redirect is a write, and the review produced an entire harvested patch with echo >. The false claims are gone. finish now fingerprints what muse produced, compares it with what it harvests, and reports out_of_band_edit with mutating_checks naming any acceptance check that accounts for part of the difference. The toolset is a strong default; the measurement is the enforcement.
Also fixed
harvestfailed on any repository with a.gitignore.git add -A -- ':(exclude,glob)__pycache__'exits 1 when git already ignores__pycache__, and the exclude list is precisely what a real repo gitignores. From the first moment a worker generated one, every harvest on that task failed andpatch.diffstopped updating. Invisible because every fixture repo in the suite is created without a.gitignore.- Three commands shipped with frontmatter that never parsed.
/muse:ask,/muse:cleanupand/muse:doctorloaded with no description and noallowed-tools. - A timed-out check left its grandchildren running, writing into a worktree about to be force-removed. Now killed as a tree — via
taskkill /F /Ton Windows, which the CI leg caught as a gap in the first fix. - Every muse-side failure reported the same sentence. Exit code and stderr now reach the round record, so an unknown flag, a bad model id and an expired credential are three different problems.
session_existsfailed OPEN, and the credential scan stopped at 5000 files without saying so. Both now fail closed and say so.- A relative
--outmoved with the current directory, sorunfrom the repo root andverifyfrom a subdirectory addressed different task directories. It resolves against the repository now.
Platform
The fleet workflow is registered (workflows/muse-supervised-fleet.js) and invoked by name, rather than shipped as a code fence the model had to transcribe — the most fragile step on the headline path. Five values are configurable at install time. SubagentStop backstops the central claim for the case where no record is written at all; SessionEnd names worktrees still holding unapplied patches. Only the fleet skill auto-triggers now. claude plugin validate --strict runs in CI.
How it was verified
The offline suite went from 99 checks to 147, and every new one was broken on purpose and confirmed to go red naming its own check. Six of those guards could not fail on the first attempt and were fixed before shipping.
CI is green on five legs: Python 3.9 / 3.11 / 3.13, Windows, and manifest validation.
The full paid live suite — real muse runs through the fleet, the supervised loop, seeding, re-run safety and session resume — is 190 passed, 0 failed.
Still unverified, and stated rather than papered over: live delegation on Windows (muse is never invoked on that leg), and whether a Bash tool call sees CLAUDE_PLUGIN_OPTION_* or a plugin-owned workflow gets ${CLAUDE_PLUGIN_ROOT} substituted — both are undocumented, so the code detects which case it is in rather than assuming.
Full detail in CHANGELOG.md.
v1.2.0 — doctor, credential scan, session resume, workflow embedding
muse types, Claude judges. Delegate bulk coding work to Muse Code workers in isolated git worktrees, each supervised by a Claude agent that runs your acceptance check itself and revises until the work is right.
Highlights
🩺 /muse:doctor
Tells you whether this machine can delegate and what it would actually use — muse version, credentials (existence only, never contents), catalog freshness, the model that resolves, your repo's git state, worktree-root writability. Three severities, a fix on every failing line, non-zero exit when blocking.
🔐 It refuses to send your credentials
Before spawning a worker, run scans the worktree — after seeding, so it sees the .env you asked it to copy — and refuses on a structurally unmistakable credential: a PEM private-key block, an AWS key id, a GitHub/Slack/Stripe/Anthropic-format token. Contributor-tier content may be used for training, and that is not undoable. Credential-shaped assignments warn rather than block, so the plugin stays usable on repos with test fixtures. Findings record file, line and kind — never the matched text.
🔁 Rounds share a muse session
A revision is now a genuine follow-up: the worker still has its brief, the files it read and its own reasoning, so feedback can say "the assertion on line 12 is wrong" without restating the task. When a session cannot be resumed, the round re-sends the brief and reports resumed: false rather than quietly losing the context.
🧩 Embed muse in your own workflow
muse delegation can be one stage of a Claude Code workflow you are writing, not just the shipped fan-out. See "Embedding muse in your own workflow" in references/workflow.md.
Fixed — found by running it, not reading it
cleanup --artifactscouldrmtreea home directory: the marker check walked unbounded and met some straystate.json. Now bounded, plus an outright refusal for home, filesystem root, repo root, and cwd/ancestors.- A failed harvest overwrote good patches with empty files — git's exit status was ignored, so a failure was presented as "the worker decided nothing needed doing".
rundeleted git branches it did not create (git branch -Ddiscards unmerged commits without asking).--timeoutkilled a shell while the real muse process ran on unbounded.- An orphaned watchdog could SIGKILL a recycled PID up to
--timeoutafter its parent died. acceptcounted any passing check, so a--collect-onlygate masked a red acceptance check.- Task ids were unvalidated —
--id ../../xwrote outside the artifact root, wherestatuscould not see it.
Verified
Full live suite 130 passed, 0 failed. Offline suite green on Python 3.9 / 3.11 / 3.13 in CI. Every guard is negative-controlled — broken on purpose and confirmed to go red. /muse:delegate and /muse:fleet exercised as real commands in fresh sessions, with the resulting patches applied and tested independently.
Install
/plugin marketplace add jellologic/claude-code-muse
/plugin install muse@claude-code-muse
Contributing — including AI agents
🤖 Autonomous agent? Start with AGENTS.md — a verified state in 60 seconds with no credentials, where to find work, and the five rules that decide whether a PR merges.
Open issues are labelled good first issue, help wanted and agent-friendly — each with a runnable acceptance check already named.
Full changelog: https://github.com/jellologic/claude-code-muse/blob/main/CHANGELOG.md