Skip to content

v2.16.3

Choose a tag to compare

@nokhodian nokhodian released this 25 Sep 08:08
· 353 commits to main since this release

[2.16.3] — 2026-09-25

Added

  • monomind doctor --json, advertised as capability doctor-json. stdout holds one JSON document with every check's result, the component id that re-runs it (-c), and how its fix is applied: auto (local and repeatable, by --fix), confirm (installs software or runs network or sudo commands, so the caller asks a person first, then passes the flag the result names) or manual. With --fix it also lists what was fixed. Everything a check or fix prints, and the subprocesses a fix runs, go to stderr. An unknown -c name comes back as the payload's error. 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-only and --offline, advertised as capabilities doctor-read-only and doctor-offline. (Fixes #335) A read-only run changes no file in the project or $HOME; it is the default under --json unless --fix or --install is given, and --read-only asks for it in the human output. --offline skips every check that uses the network. A check that cannot run in the mode is reported with status skipped and a skipped_reason (read-only or offline); the JSON payload also gains read_only, offline and summary.skipped. --read-only --fix and --offline --install are refused. mono-agent can now include monomind's checks in its read-only monoagentcli doctor default. Contract: doc/agent-exec-protocol.md §10.1.
  • agent scan --json entries carry install and login_hint. install is the install hint in a shape a caller can run without a shell — npm packages, an https install script for bash/sh, or manual for anything else — and login_hint is 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 is manual. mono-agent's agent install and its Agents page use them.
  • Claude sees the prompt's pick as one [PICK] line. The UserPromptSubmit hook now prints [PICK] agent: <name> · skill: <invoke> into Claude's context when it is confident: a Jev decision-model answer at or above MONOMIND_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 frontmatter name, the value the Task tool takes as subagent_type. Ties and weak overlap print nothing. The line is printed even under MONOMIND_HOOK_QUIET, which monomind init sets; the other banners stay quiet. Task notifications, reminder-only turns, slash-command expansions and local-command output get no pick. The generated CLAUDE.md tells Claude to follow a [PICK] line unless it is clearly wrong and to call the pick tool before choosing a subagent itself.
  • pick MCP tool (mcp__monomind__pick). Input { task, kind?: "agents" | "skills" | "both", categories?, top?: 1-20 }; it returns the same JSON as monomind pick --json plus a one-line summary. 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 PreToolUse hook on Task|Agent spawns writes .monomind/pick-adherence.jsonl (the session's pick, the subagent_type actually spawned, followed); it only observes. .claude/helpers/pick-stats.cjs folds adherence and SubagentStop outcomes into .monomind/pick-stats.json at 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 in monomind pick and 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 --explain shows score = baseScore × prior and the pick history, and readPickStats(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 to MONOMIND_JEV_PICK_MIN_CONFIDENCE (default 0.25, or --min-confidence) it is kept and flagged lowConfidence: true. Jev tail entries under 0.02 are dropped. Each list in the JSON now carries source (jev, keyword, or keyword-fallback when a configured model gave no usable answer). Agents print by their spawnable name.
  • pnpm run pick:eval and monomind doctor -c pick. The eval scores 60 tasks in tests/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, in verify and CI. Every subagent_type, agentSlug and Skill(...) name in shipped skills, commands, the init generators and the CLAUDE.md agent 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, specialagent and a few others, which now declare it) surface only when a task names them.
  • Org task provenance and org_skill_search. Every task created by org_task records assignedBy (auto or explicit); an auto-assigned task also records pick (method, confidence or score, top three candidates), and suggestions and loads are recorded as suggestedSkills and loadedSkills. Audit events task-auto-assigned, task-skills-suggested and skill-loaded carry the same data. Roles with skills or skill_pool get org_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, tags and one category (core, architecture, engineering, testing, security, devops, github, marketing, design, coordination, data-ai, specialized), and every description fits in 160 characters. The registry stores whenToUse, tags and vibe, and the picker leads each agent's text with when_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 in org-skills/TAGS.md.
  • summary in monomind pick --json, the same one-line agent: <name> · skill: <invoke> the MCP tool returns.

Changed

  • One index for agents and skills, shared by every selector. The prompt hook and monomind pick now 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/skills and commands, plus ~/.claude/skills for 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 tagged source: "platform" or "org"; an Org skill's invoke is mcp__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 registry now reports duplicate slugs and extra agent roots.
  • .claude/helpers/skill-registry.json is generated per machine and no longer shipped. monomind init, init upgrade, monomind pick and 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.cjs drops 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_explain and route task rank through the same code as monomind pick, so they can no longer disagree, and every agent they return is a spawnable name (coder when nothing ranks). hooks_route no longer takes useSemanticRouter and no longer blends memory-bridge or ReasoningBank matches; semanticMatches is always empty and topK (1-20) sets the count. route task's fixed eight-type table (architect, optimizer, debugger, documenter, …) is gone and route list-agents lists the registry. route semantic, hooks_route_semantic and agent spawn --task ask the picker first: a decision-model answer at or above 0.6, then the @monoes/routing keyword rules, then a clearly leading keyword pick; embeddings and the Haiku fallback run only after that. agent spawn --type accepts any registry agent name, and the old fixed types map to one (architect → Software Architect, security-auditor → Security Engineer, …). Breaking for guidance_recommend callers: the recommended agents moved from each capability area's agents list to one top-level agents array ({ name, confidence, reason }) from the picker.
  • @monoes/routing 1.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 the pick MCP tool, then a local monomind pick (never through npx), 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 missing mastermind-<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-manager is scoped to consensus-protocol security, so application security goes to Security Engineer. The reengineer-squad tester is renamed reengineer-tester so it no longer collides with the core tester.
  • Org auto-assignment picks the specific role, or refuses. org_task's assignee: "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.jsonl stores 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 and shown (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 scan writes nothing. It no longer runs the startup update check (which wrote ~/.monomind/update-state.json after a network call) or the subsystem init (which wrote .monomind/registry.json in the current directory). Callers such as mono-agent run it on a timer to show installed runtimes. The agent CLIs' own --version probes may still write their own state.
  • init upgrade refreshes the .gemini/helpers copy too. init writes the helper tree to .gemini/helpers as well as .claude/helpers, and Antigravity's status bar runs .gemini/helpers/statusline.cjs from it, but init upgrade only 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), and doctor reports 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 --json and the org --json commands, so callers such as mono-agent failed to parse it ("invalid character '↑'"). stdout now holds only the command's own output.
  • doctor --json no longer writes to the folder it checks or to $HOME. (Fixes #335) A plain doctor --json rewrote .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 -shm file, and filled ~/.npm with cache entries and debug logs. Read-only runs now do none of this (see Added). The TypeScript check no longer runs npx tsc --version, which downloaded the unrelated tsc package from the registry in a project without TypeScript; it reads the version of the project's own typescript package.
  • -v debug lines go to stderr. [DEBUG] and [TRACE] lines, and the "Completed in …ms" line, were written to stdout, so -v with a --json command 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.json left every agent's capabilities empty, because the builder skipped the expertise: list inside a capability: block, and stored a literal | as the description of the 17 agents that write it as a YAML block scalar. It now reads both, so monomind pick and 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 category default and gave 49 agents two registry entries; they are removed. The shipped package tree was not affected.
  • org_task_cancel stops 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_done on 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 printed bwrap: : No such file or directory among 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 leading Exit code N line is allowed, so a failed call such as Exit 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 timeout in seconds, and the generated settings wrote milliseconds: 5000 allowed 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 agentActuallyUsed with its own recommendation; only a real Task/Agent spawn sets it. SubagentStop logs the subagent from the event's agent_type as actualAgent and the pick as suggestedAgent, which were swapped, and PostTask reads agent_type too. 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.cjs no 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 with pick-rank.cjs over 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_route gap 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-agent writes valid Org Runtime v2 roles, and mastermind-createorg seeds role responsibilities from the agent registry.
  • The generated settings no longer mention MONOMIND_HOOK_VERBOSE. The MONOMIND_HOOK_QUIET comment offered it as the opt-out, but nothing reads it; the opt-out is removing MONOMIND_HOOK_QUIET or setting it to 0.
  • 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.json exists, lists it active with the jev target, and its package digest verifies. Before, a missing state file let the projection's own jev:yes marker through, and user skills were never checked. doc/privacy.md now lists what the picker sends.
  • The picker writes nothing outside a project. monomind pick, route, agent and doctor run from $HOME or a folder that is not a project build their catalogs in memory; they no longer create .monomind/registry.json or 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 from hooks_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.json are 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 pick MCP tool, hooks_route, route task and guidance_recommend now apply it like monomind pick and 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 --settings brings old installs up to date. It adds the monomind hooks the install lacks (the Task|Agent adherence 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 check hook-settings warns about missing pick hooks and millisecond timeouts, and the registry check counts agents missing when_to_use.
  • Pick guidance works before the MCP tool is published. Generated CLAUDE.md and CAPABILITIES.md say to call mcp__monomind__pick when available, else monomind 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 --type matches 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, accessibility and error-handling-patterns are gone; use database-migrations, team-communications, accessibility-compliance and error-handling. A role that names a removed skill in skills or skill_pool must be updated.
  • hooks_route's useSemanticRouter input, and the @monoes/routing routes and rules listed under Changed.
  • cleanup --force reaps 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 --force itself, claude, or claude-agent-sdk --output-format next 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 after node/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 undefined when the suite ran inside a Claude role. The role's own BASH_DEFAULT_TIMEOUT_MS/BASH_MAX_TIMEOUT_MS passed 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.