v2.16.3
[2.16.3] — 2026-09-25
Added
monomind doctor --json, advertised as capabilitydoctor-json. stdout holds one JSON document with every check's result, thecomponentid that re-runs it (-c), and how its fix is applied:auto(local and repeatable, by--fix),confirm(installs software or runs network orsudocommands, so the caller asks a person first, then passes the flag the result names) ormanual. With--fixit also lists what was fixed. Everything a check or fix prints, and the subprocesses a fix runs, go to stderr. An unknown-cname comes back as the payload'serror. mono-agent uses this to show and fix monomind's checks in its Settings › System health, per project. Contract:doc/agent-exec-protocol.md§10.monomind doctor --read-onlyand--offline, advertised as capabilitiesdoctor-read-onlyanddoctor-offline. (Fixes #335) A read-only run changes no file in the project or$HOME; it is the default under--jsonunless--fixor--installis given, and--read-onlyasks for it in the human output.--offlineskips every check that uses the network. A check that cannot run in the mode is reported with statusskippedand askipped_reason(read-onlyoroffline); the JSON payload also gainsread_only,offlineandsummary.skipped.--read-only --fixand--offline --installare refused. mono-agent can now include monomind's checks in its read-onlymonoagentcli doctordefault. Contract:doc/agent-exec-protocol.md§10.1.agent scan --jsonentries carryinstallandlogin_hint.installis the install hint in a shape a caller can run without a shell —npmpackages, an https installscriptfor bash/sh, ormanualfor anything else — andlogin_hintis the runtime's sign-in command, as text to show a person — never something to run. An install script URL must be a plain https URL; a hint with shell syntax, credentials in the URL or an npm version range ismanual. mono-agent'sagent installand its Agents page use them.- Claude sees the prompt's pick as one
[PICK]line. TheUserPromptSubmithook now prints[PICK] agent: <name> · skill: <invoke>into Claude's context when it is confident: a Jev decision-model answer at or aboveMONOMIND_JEV_MIN_CONFIDENCE(0.6), or a keyword agent with a relevance score of at least 2 and a 1.5× lead over the runner-up (a keyword skill needs a score of 4).<name>is the agent's frontmattername, the value the Task tool takes assubagent_type. Ties and weak overlap print nothing. The line is printed even underMONOMIND_HOOK_QUIET, whichmonomind initsets; the other banners stay quiet. Task notifications, reminder-only turns, slash-command expansions and local-command output get no pick. The generatedCLAUDE.mdtells Claude to follow a[PICK]line unless it is clearly wrong and to call thepicktool before choosing a subagent itself. pickMCP tool (mcp__monomind__pick). Input{ task, kind?: "agents" | "skills" | "both", categories?, top?: 1-20 }; it returns the same JSON asmonomind pick --jsonplus a one-linesummary. It is in the core tool set, so the advertised MCP tool list grows by one.- The hooks log whether a pick was followed, and a bounded prior learns from it. A new
PreToolUsehook onTask|Agentspawns writes.monomind/pick-adherence.jsonl(the session's pick, thesubagent_typeactually spawned,followed); it only observes..claude/helpers/pick-stats.cjsfolds adherence and SubagentStop outcomes into.monomind/pick-stats.jsonat SubagentStop and SessionEnd. An agent with at least 5 observations gets a factor between 0.85 and 1.15 from its success and adoption rates, applied to keyword agent scores inmonomind pickand the prompt hook. The largest swing (about 1.35×) is below the 1.5× lead a[PICK]needs, so history breaks near-ties but never overturns a clear match; Jev rankings are not re-ranked.monomind pick --explainshowsscore = baseScore × priorand the pick history, andreadPickStats(root)is exported. In org runs, auto-assignment and per-task skill suggestions break keyword near-ties the same way from the run's own finished tasks (3 outcomes minimum). monomind pick --min-confidence,--explain, and low-confidence rankings. A Jev answer below 0.6 is no longer thrown away when a person or Claude reads the result: down toMONOMIND_JEV_PICK_MIN_CONFIDENCE(default 0.25, or--min-confidence) it is kept and flaggedlowConfidence: true. Jev tail entries under 0.02 are dropped. Each list in the JSON now carriessource(jev,keyword, orkeyword-fallbackwhen a configured model gave no usable answer). Agents print by their spawnable name.pnpm run pick:evalandmonomind doctor -c pick. The eval scores 60 tasks intests/pick-eval/(each listing every acceptable agent and skill) with the keyword ranker in-process, or through the real picker with--jev; CI holds a floor on a frozen catalog snapshot. Keyword picks now get agents right at top-1 on 47/60 tasks and skills on 49/59; Jev gets 59/60 and 58/59. Before this work, on the original 40 tasks, keyword got 23/40 and 27/40 and Jev 34/40 and 39/40.doctor -c pick(opt-in, not in the default run) reports registry and skill-index counts and freshness, whether a decision model is configured, the eval score when the project carries the set,[PICK]adherence, and subagent success when the pick was followed versus overridden.pnpm run lint:agent-refs, inverifyand CI. Everysubagent_type,agentSlugandSkill(...)name in shipped skills, commands, the init generators and theCLAUDE.mdagent rosters must name an agent or skill that exists.- Skills can declare
pick: low. The skill index records it and the keyword ranker keeps 35 % of such a skill's score, so admin and meta skills (the org management pages,specialagentand a few others, which now declare it) surface only when a task names them. - Org task provenance and
org_skill_search. Every task created byorg_taskrecordsassignedBy(autoorexplicit); an auto-assigned task also recordspick(method, confidence or score, top three candidates), and suggestions and loads are recorded assuggestedSkillsandloadedSkills. Audit eventstask-auto-assigned,task-skills-suggestedandskill-loadedcarry the same data. Roles withskillsorskill_poolgetorg_skill_search, which ranks the whole library by name and description; loading stays limited to the role's own skills. - Agent frontmatter for picking. Every bundled agent now has
when_to_use,tagsand onecategory(core, architecture, engineering, testing, security, devops, github, marketing, design, coordination, data-ai, specialized), and every description fits in 160 characters. The registry storeswhenToUse,tagsandvibe, and the picker leads each agent's text withwhen_to_use. Org skills get the same treatment: all 376 descriptions open with a sentence of at most 160 characters ("Use when…", or "Org role guidance…" for the 36 that share a name with an agent), with 3-5 tags each from the new 99-tag vocabulary inorg-skills/TAGS.md. summaryinmonomind pick --json, the same one-lineagent: <name> · skill: <invoke>the MCP tool returns.
Changed
- One index for agents and skills, shared by every selector. The prompt hook and
monomind picknow load candidates through one loader (.claude/helpers/jev-catalog.cjs) and rank exactly the same set: the registry's agents (deprecated ones left out), then platform skills (the project's.claude/skillsand commands, plus~/.claude/skillsfor names the project lacks,origin: "user"), then Org-library skills (bundled,~/.monomind/org-skills, project and active catalog entries) whose name is not already a platform skill, a known alias of one, or an agent. Each ranked skill is taggedsource: "platform"or"org"; an Org skill'sinvokeismcp__monomind__org_skill_show {"name":"<name>"}. README, overview and helper-only skill files are no longer entries. The agent registry is built for the project root, awaited when missing or stale, written atomically and never replaced by an empty one.doctor -c registrynow reports duplicate slugs and extra agent roots. .claude/helpers/skill-registry.jsonis generated per machine and no longer shipped.monomind init,init upgrade,monomind pickand SessionStart build it when it is missing or older than its sources, and it is gitignored. A project that committed the file can delete it from version control.- The keyword ranker is BM25-style.
.claude/helpers/pick-rank.cjsdrops stopwords, stems words lightly, weights each word by its rarity across the catalog, normalises description matches by length and scales by the share of task words matched. The old bonus for a category prefix in an id (engineering-,mastermind-) is gone. It is the fallback of every picker and builds the shortlist Jev chooses from. - Every agent selector wraps the central picker.
hooks_route,monomind hooks route,hooks_pre-task,hooks_explainandroute taskrank through the same code asmonomind pick, so they can no longer disagree, and every agent they return is a spawnable name (coderwhen nothing ranks).hooks_routeno longer takesuseSemanticRouterand no longer blends memory-bridge or ReasoningBank matches;semanticMatchesis always empty andtopK(1-20) sets the count.route task's fixed eight-type table (architect,optimizer,debugger,documenter, …) is gone androute list-agentslists the registry.route semantic,hooks_route_semanticandagent spawn --taskask the picker first: a decision-model answer at or above 0.6, then the@monoes/routingkeyword rules, then a clearly leading keyword pick; embeddings and the Haiku fallback run only after that.agent spawn --typeaccepts any registry agent name, and the old fixed types map to one (architect→Software Architect,security-auditor→Security Engineer, …). Breaking forguidance_recommendcallers: the recommended agents moved from each capability area'sagentslist to one top-levelagentsarray ({ name, confidence, reason }) from the picker. @monoes/routing1.1.1 routes name agents that exist. Every route and keyword rule names a bundled agent's spawnable name (Security Engineer,DevOps Automator, …) instead of slugs that did not ship. Routes and rules with no matching agent are removed, not redirected: the game-development routes and the Blender, Unreal, Unity and Godot rules, the Salesforce rule and route, the TikTok and LinkedIn routes, and the ZK-proof rule.- Skills and commands pick their specialists instead of naming them. The mastermind skills and commands ask the
[PICK]line, then thepickMCP tool, then a localmonomind pick(never throughnpx), and keep a short fallback of agents that exist. About 75 agent and skill names that did not exist are fixed (backend-dev,code-review-swarm,Trend Researcher,Skill("mastermind-do"), …)./mastermind:<x>references point at/mastermind-<x>where only a skill exists. The content, marketing, sales, ops and finance commands spawn a picked specialist instead of a missingmastermind-<domain>skill.mastermind-agent-select's category map and fallbacks name real registry categories and agents. - Near-duplicate agents are deprecated.
Code Reviewer→reviewer,mobile-dev→Mobile App Builder,monoswarm-pr→pr-manager,monoswarm-issue→issue-tracker. They are no longer picked but can still be spawned by name.security-manageris scoped to consensus-protocol security, so application security goes toSecurity Engineer. The reengineer-squad tester is renamedreengineer-testerso it no longer collides with the coretester. - Org auto-assignment picks the specific role, or refuses.
org_task'sassignee: "auto"never picks an endpoint role or the caller, reads the task's brief, weights words by how few roles mention them, needs a minimum score, and breaks ties by specificity and then by open work instead of declaration order. A tie that survives, or no role clearing the bar, refuses the call and names the closest roles. Per-task skill suggestions now work without a decision model, by keyword match over the role's pool. - Route records say what was picked and shown.
.monomind/route-outcomes.jsonlstores a prompt hash and a secret-redacted 120-character preview instead of the first 500 characters of the prompt, plus the candidates, provider, session id andshown(whether a[PICK]line was printed). Each session's latest pick is kept in.monomind/routes/<sessionId>.json, so concurrent sessions no longer read each other's picks.
Fixed
agent scanwrites nothing. It no longer runs the startup update check (which wrote~/.monomind/update-state.jsonafter a network call) or the subsystem init (which wrote.monomind/registry.jsonin the current directory). Callers such as mono-agent run it on a timer to show installed runtimes. The agent CLIs' own--versionprobes may still write their own state.init upgraderefreshes the.gemini/helperscopy too.initwrites the helper tree to.gemini/helpersas well as.claude/helpers, and Antigravity's status bar runs.gemini/helpers/statusline.cjsfrom it, butinit upgradeonly refreshed.claude/helpers, so upgraded projects kept the first install's helpers there. The Gemini copy now gets the same refresh (only where it exists; files the bundle does not ship are kept), anddoctorreports stale files in it under Helper Files.- The "update available" notice goes to stderr. It was written to stdout on the first run of any command after a release, ahead of the JSON of
agent scan --json,doctor --jsonand the org--jsoncommands, so callers such as mono-agent failed to parse it ("invalid character '↑'"). stdout now holds only the command's own output. doctor --jsonno longer writes to the folder it checks or to$HOME. (Fixes #335) A plaindoctor --jsonrewrote.monomind/registry.json(from the CLI's startup refresh and the Agent Registry check), created the memory database under~/.monomind/projects/to count the knowledge graph, wrote the update-check state, updated the monograph db's-shmfile, and filled~/.npmwith cache entries and debug logs. Read-only runs now do none of this (see Added). The TypeScript check no longer runsnpx tsc --version, which downloaded the unrelatedtscpackage from the registry in a project without TypeScript; it reads the version of the project's owntypescriptpackage.-vdebug lines go to stderr.[DEBUG]and[TRACE]lines, and the "Completed in …ms" line, were written to stdout, so-vwith a--jsoncommand put them ahead of the JSON. They now go to stderr, like[INFO].- The agent registry reads agent frontmatter correctly and no longer holds duplicates.
.monomind/registry.jsonleft every agent'scapabilitiesempty, because the builder skipped theexpertise:list inside acapability:block, and stored a literal|as the description of the 17 agents that write it as a YAML block scalar. It now reads both, somonomind pickand Jev see each agent's expertise and description. The repo's own.claude/agents/also held 88 flat copies of agents that live in category folders (committed by accident in 2026-09), which put 63 agents in categorydefaultand gave 49 agents two registry entries; they are removed. The shipped package tree was not affected. org_task_cancelstops the assignee's work on the task. On the 2.16.2 release run the coordinator cancelled task-25 while the fixer was mid-turn on it. Nothing told the fixer, which worked on for 25 minutes and committed a fix that was later integrated after the final audit. The assignee is now sent[task:<id>] CANCELLED … — stop now, do not commit or report further work for it. In task scope (session_scope: 'task'), a running process for that task is also ended, the way a sandbox fault ends one, since mail only arrives when a turn ends. Processes for the role's other tasks are left alone.org_task_doneon a cancelled task is refused with the cancel reason and the instruction to stop, where it used to say the close "would notify its creator about work that was reported long ago".org_task_cancel's description says this, so the org tool list changes once.- A role's Bash sandbox no longer fails on an SDK stub that has gone away. On the 2.16.2 release run docs-writer's Bash calls failed with
bwrap: Can't find source path ~/.claude/local. When a read-only directory holds the role's cwd or~/.claude, monomind passes the SDK that directory's existing entries (#323). Those entries included the empty mount-point stubs another sandbox had made, and the SDK deletes a stub when the sandbox that made it ends. A stub that was listed when the role's process started but gone by a later Bash call made bwrap fail. Empty regular files are now left out of that list. The SDK already denies those names itself. - A command that runs bwrap itself no longer counts as the role's sandbox failing. Any Bash result starting
bwrap:was taken as the OS sandbox failing to start, and two in a row restart the role's process. On the 2.16.2 release run cli-qa's orphan-reaper repros ran bwrap on purpose and printedbwrap: : No such file or directoryamong other output, which was counted. A result now counts only when it is wholly one of the messages bwrap dies with while it sets the sandbox up (Can't …,Creating …,setting up …,execvp …, …). The tool's leadingExit code Nline is allowed, so a failed call such asExit code 1+bwrap: Can't find source path …, which was missed before, is counted now. - Hook timeouts are written in seconds. Claude Code reads a hook's
timeoutin seconds, and the generated settings wrote milliseconds:5000allowed a hung hook about 83 minutes. They now write seconds (12 for the prompt hook, which covers the longest Jev window). - Route outcomes record the agent that actually ran. The prompt hook no longer fills
agentActuallyUsedwith its own recommendation; only a real Task/Agent spawn sets it. SubagentStop logs the subagent from the event'sagent_typeasactualAgentand the pick assuggestedAgent, which were swapped, and PostTask readsagent_typetoo. Session-end success reads the tail of a large outcomes file instead of skipping it. - SessionStart rebuilds a stale skill index. A missing
skill-registry.json, or one older than.claude/skills, is rebuilt at session start instead of serving skills that no longer exist. router.cjsno longer selects agents or skills. Most slugs in its keyword agent table were not registry agents; the table is gone, and the prompt hook ranks keyword agents and skills withpick-rank.cjsover the shared catalogs (a keyword skill needs a score of at least 3 and a 1.25× lead).- Recommendations name agents that exist.
guidance_recommend's capability areas and workflows,route coverage/coverage_routegap assignments and the prompt hook's intelligence advisory named agents that do not ship (security-architect,backend-dev,code-review-swarm,swarm-pr, …); they now name registry agents. mastermind-new-agentwrites valid Org Runtime v2 roles, andmastermind-createorgseeds role responsibilities from the agent registry.- The generated settings no longer mention
MONOMIND_HOOK_VERBOSE. TheMONOMIND_HOOK_QUIETcomment offered it as the opt-out, but nothing reads it; the opt-out is removingMONOMIND_HOOK_QUIETor setting it to0. - Catalog skills reach the decision model only with approval. A skill projected from the catalog, including a copy in
~/.claude/skills, is sent to Jev only when.monomind/catalog/state.jsonexists, lists it active with thejevtarget, and its package digest verifies. Before, a missing state file let the projection's ownjev:yesmarker through, and user skills were never checked.doc/privacy.mdnow lists what the picker sends. - The picker writes nothing outside a project.
monomind pick,route,agentanddoctorrun from$HOMEor a folder that is not a project build their catalogs in memory; they no longer create.monomind/registry.jsonor a skill index there. The skill index is never replaced by an empty one. - Concurrent sessions no longer lose route records. Appends, outcome joins and rotation of
.monomind/route-outcomes.jsonl, from the hook and fromhooks_route, hold one lock file; in a two-process test 28 of 150 records were lost before and none after. - Slash commands no longer count as recommendations. A slash-command route names no agent, and a spawn is compared only with its own session's route, so adherence and the outcome prior are not skewed.
- The outcome prior stays bounded. Counts read from
pick-stats.jsonare sanitised and the factor is clamped to ×0.85–1.15, so a damaged file cannot reorder picks or produce NaN scores. - Every selector ranks with the outcome prior. The
pickMCP tool,hooks_route,route taskandguidance_recommendnow apply it likemonomind pickand the hook, so they return the same order. - No pick for trivial prompts, and non-Latin prompts rank. Prompts with fewer than three content words get no
[PICK]; the keyword tokenizer handles Unicode letters, folds accents and splits CJK text into bigrams. - SubagentStart/SubagentStop are silent under
MONOMIND_HOOK_QUIET, and two same-type subagents finishing in the same millisecond both count. init upgrade --settingsbrings old installs up to date. It adds the monomind hooks the install lacks (theTask|Agentadherence hook, SubagentStart/Stop capture) and converts monomind hook timeouts written in milliseconds to seconds; user hooks are untouched. Upgrade also refreshes bundled agents whose body the user has not edited. New doctor checkhook-settingswarns about missing pick hooks and millisecond timeouts, and the registry check counts agents missingwhen_to_use.- Pick guidance works before the MCP tool is published. Generated
CLAUDE.mdandCAPABILITIES.mdsay to callmcp__monomind__pickwhen available, elsemonomind pick -t "<task>" --json. - A cancelled org task no longer reaches its assignee after the cancel. A task still held for dispatch is withdrawn without a notice, a task that was never sent no longer wakes its assignee, and a cancel that arrives while a task-scoped process is starting ends it.
agent spawn --typematches names case-insensitively and takes capabilities from the resolved agent.- Test suites cannot reach a hosted decision model. Both vitest configs clear Jev provider environment before running.
Removed
- Four duplicate Org skills.
database-migration,internal-comms,accessibilityanderror-handling-patternsare gone; usedatabase-migrations,team-communications,accessibility-complianceanderror-handling. A role that names a removed skill inskillsorskill_poolmust be updated. hooks_route'suseSemanticRouterinput, and the@monoes/routingroutes and rules listed under Changed.cleanup --forcereaps an orphaned SDK process under a bwrap sandbox. (Fixes #333) In a sandbox, bwrap stays pid 1 and keeps the whole wrapped Bash command in its own cmdline. Any word in that text could make the reaper treat it as a live session and skip every orphan beneath it:monomind cleanup --forceitself,claude, orclaude-agent-sdk --output-formatnext to each other. The 2.16.2 fixes narrowed this case but did not close it. An ancestor now counts as a live session only when the program it runs is Claude Code, monomind, or the SDK: its first word, or the script afternode/bun. Words later on the line are ignored. A Claude Code, monomind or SDK process that a shell starts is its own process, so it still protects the processes under it. Verified in a real bwrap PID namespace with the issue's repro: the orphan is reaped and the live sibling is kept.- The Bash-timeout test passes inside a Claude org role. (Fixes #334) The test "a non-Claude runtime session env does not carry them" failed with
expected '600000' to be undefinedwhen the suite ran inside a Claude role. The role's ownBASH_DEFAULT_TIMEOUT_MS/BASH_MAX_TIMEOUT_MSpassed through the parent env into the session env the test inspects. The test now clears both variables for each case. Runtime behavior is unchanged: monomind still adds these variables only for Claude roles and still passes the parent env through to every runtime.
npm: npm install -g monomind@2.16.3 — published packages: monomind@2.16.3, @monoes/monomindcli@2.16.3, @monoes/routing@1.1.1, @monoes/memory@1.0.20, monofence-ai@1.0.6.