Skip to content

v2.19.0

Choose a tag to compare

@nokhodian nokhodian released this 29 Sep 17:33
· 695 commits to main since this release

[2.19.0] — 2026-09-29

Changed

  • The MCP server advertises a 20-tool core by default (#410). tools/list sent 71 tools (34.7 KB, about 8.7k tokens on clients that load schemas eagerly), and 45 of them only read or write state files: agent_*, task_*, session_*, config_*, system_*, guidance_*, hooks_* and mcp_status. The default roster is now monograph (build, query, suggest, impact, context, neighbors), pick, org_skill_show, monomind_tool_search, knowledge_search/ingest/remove, monodesign_detect/fix/palette, and the five memory tools the generated CLAUDE.md and the KG nudge name (memory_pattern-store, memory_feedback, memory_kg_ingest, memory_kg_search, memory_kg_stats), 14.6 KB in all. Every other tool is still callable by name and found through monomind_tool_search; MONOMIND_MCP_FULL=1 still advertises all of them.

Added

  • Coder mode on every full-access runtime (#431, agent-exec protocol rev 19). agent exec now drives claude, codex, copilot, antigravity, opencode, kimicode, grok, qwen, pi — and the new Cline, Aider and DeepSeek Harness (dsh) runners — with matched start/status/tool/done events and full-access editing/commands, instead of only claude and codex having real coverage. --effort off|low|medium|high|xhigh|max (rev 16) is now honored per runtime where the vendor CLI supports it and reported as a status notice where it is ignored. agent exec retries a transient provider rate limit (HTTP 429), now its own rate-limited code distinct from quota (rev 20), up to 3 attempts with ~2s/~4s backoff and jitter or the provider's Retry-After hint, each wait capped at 30s and kept inside --timeout, emitting a status notice before each retry. Cline turns run scoped by default (file edits inside the project only; approval-gated tools refused) unless given full access. monomind init --target agents and --target cline/--target aider write only the files those runtimes read (AGENTS.md, or nothing extra) instead of every platform's files.
  • agent exec --access read (#388, agent-exec protocol rev 21, capability agent-exec-access-read). A turn that can read the project and the web but cannot edit files, run arbitrary commands or start subagents. Allowed: Read, Grep, Glob, LS, WebSearch, WebFetch, TodoWrite, Skill, ToolSearch, caller (stdio) tools, and shell commands that start with git status|diff|log|show|blame, ls, cat, head, tail, wc, rg, grep or find (plus any --allow-bash-prefix entries) with no pipes, redirects, chaining, substitution or subshells, and no find -exec/-delete/-fprint…, rg --pre or git --output/--ext-diff. Edit, Write, MultiEdit, NotebookEdit, other shell commands and Task/Agent are denied (tool_activity end denied: true). Works with --settings. claude enforces it itself; codex runs --sandbox read-only (never danger-full-access, whatever the git level) and pi/pi-rpc run --tools read,grep,find,ls. Every other runtime, opencode included, answers error {code:"unsupported"}. agent scan --json entries gain access_modes (e.g. ["scoped","read","full"]).
  • Caller tools with agent exec --access full, and parallel caller calls (#389, agent-exec protocol rev 22, capability agent-exec-full-access-tools). --access full --tools stdio --tools-file … is supported and tested on claude and every other runtime with full_access: true: caller tools sit next to the native tools and use the same tool_call/tool_result frames and --tool-timeout as scoped mode (no monomind maximum; bounded by --timeout, and on claude by Claude Code's MCP call timeout — a 130s call was verified). When one assistant message makes several caller calls, all their tool_call frames are sent before monomind waits for any result, and results match by id in any order (claude marks caller tools readOnlyHint so Claude Code runs them concurrently; fence runtimes start a round's calls together). agent scan --json entries gain caller_tools and caller_tools_with_full_access; a runtime that cannot take caller tools in the requested mode answers error {code:"unsupported"} instead of dropping them. --allow-bash-prefix is still rejected with --access full.
  • agent exec reports what the vendor CLI really runs with, and --sandbox picks its own sandbox (#396, agent-exec protocol rev 23, capability agent-exec-sandbox). The default is unchanged: without the new flag, a non-org turn still runs codex with danger-full-access, grok without a sandbox, and copilot, qwen, antigravity and others with approvals off. The start event now says so, with native_sandbox (read-only, workspace-write, full, none, or monomind for claude, where monomind enforces access itself) and approvals (off, on, n/a), and each agent scan --json entry gives the same defaults plus sandbox_modes. --sandbox read-only|workspace-write|full uses the CLI's own sandbox on codex, grok and dsh. full means today's default on every runtime. Other modes on other runtimes fail with unsupported. The flag can tighten an org role's git level but never loosen it. --access read always runs codex read-only, and --access read --sandbox full is a usage error. Callers that don't want an unsandboxed turn (e.g. mono-agent) should pass --sandbox.

Fixed

  • The per-prompt Second Brain lookup only sends the prompt to a loopback server (#402). The route hook POSTed every substantive prompt to the url in .monomind/control.json without checking where it pointed, so a tampered or committed control.json could send prompts to any host. The POST now happens only when that url is http(s) to 127.0.0.1, localhost or ::1 (no credentials in the url); otherwise the hook skips it and uses the local keyword fallback.
  • monobrowse no longer leaves Chromium profiles in /tmp (#395). Every browser monobrowse launched got a fresh --user-data-dir under os.tmpdir() (monomind-browser-*, monomind-browse-*) that nothing deleted, so they piled up until /tmp ran out of quota. A profile dir monobrowse created is now deleted once its Chrome has exited: on a graceful close, on the kill fallback, on browse close from a later process (the session record carries a new ownsUserDataDir flag), and when a launch fails. Every launch also sweeps dirs left by a crashed or killed process: only exact monobrowse names directly in tmpdir, real directories (never symlinks), older than 10 minutes, whose owning pid is dead and that no live Chrome still uses (/proc command lines on Linux, the profile's SingletonLock everywhere). A caller-supplied userDataDir is never deleted.
  • The provider API key file and memory databases are gitignored (#398). monomind.config.json (where providers configure -k stores the key in plain text), .swarm/ and .claude/memory.db were not ignored after init, and doctor's gitignore check still passed. Doctor now requires all three, and doctor --fix (which init runs) adds any that are missing to the root .gitignore. providers configure prints where it wrote the key and warns when that file is not gitignored.
  • mastermind-budgets now sets caps the org runtime enforces (#400). Its set wrote .monomind/orgs/<org>-budgets.json, which nothing in the runtime reads, so a budget set through the skill capped nothing. It now edits roles[].budget_usd, roles[].budget_tokens and run_config.budget_tokens in the org definition, validates it and runs monomind org reload (the caps hot-reload with spend kept). show and alert read spend from monomind org costs --format json and the run's budget events. There is no org-wide USD cap, and the skill now says so and refuses to fake one. reset is replaced by clear, which removes a role's own caps.
  • mastermind-routines maps onto the org schedule (#400). It wrote per-agent cron routines to <org>-routines.json, which the runtime never runs. It now sets or clears the org's schedule interval (applied by monomind org serve at start), pauses and resumes with org pause/org resume, and triggers a run with org run. list flags any entries left in the old file as not enforced.
  • The dashboard's Budgets data shows the enforced limits. GET /api/org/:name/budgets takes org_budget and agent_budgets from the org definition (run_config.budget_tokens, each role's budget_usd/budget_tokens or its policy.maxUsd/maxTokens) instead of <org>-budgets.json.
  • cleanup --force no longer leaves hooks pointing at deleted helpers (#401). After a default init, cleanup --force --purge-data removed .claude/helpers/ but kept all 17 monomind hooks in .claude/settings.json, so every prompt and tool call then failed with Cannot find module …/hook-handler.cjs. Cleanup now rewrites .claude/settings.json and .gemini/settings.json in place, dropping only the hook entries and statusLine whose command runs a helper the same plan removes (plus matcher groups and events left empty); other keys and user hooks stay, and a git-tracked settings file is still never rewritten. It also removes the monomind server from .kimi-code/mcp.json, the [mcp_servers.monomind] table from .codex/config.toml and init's npx monomind bash rules from opencode.json. init now records hashes for the converted .opencode/agent, .opencode/command and .kimi-code/agents files, .kimi-code/plugin/kimi.plugin.json and .gemini/helpers/statusline.sh, so cleanup can prove they are untouched installs and remove them; ones you edited are kept. The dry run lists every edit.
  • The SessionStart session-restore hook no longer parses every transcript (#403). After quickSummary() went cache-first for #42, session-restore still called quickSummaryData(), which re-parsed every transcript under ~/.claude/projects synchronously (tens of seconds, up to 140 s on active machines). That blocked the event loop, so the handler's own safety timer never fired and Claude Code killed the hook at 15 s. quickSummaryData() now reads the same cached totals as quickSummary() and starts the detached refresh when the cache is stale or missing, at most once per process. A cold cache writes no token-summary.json on that session start.
  • monograph_suggest task= returns the nodes relevant to the task (#406). Suggest answered only from AMBIGUOUS/INFERRED edges (about 3% of a real graph), so most task descriptions got "No suggestions for this task. Run monograph_build first." even on a fully built index. With task= it now lists the top limit (default 10) nodes ranked by the same search monograph_query uses, each with file:line, followed by the graph-topology questions about them when any exist. It says "Run monograph_build first" only when the graph has no nodes; a built graph with no match for the task says that no nodes match.
  • monograph no longer indexes monomind's own asset mirrors, gitignored files or anonymous closures as searchable symbols (#404). In a fresh 5-file project, 30,405 of ~30,430 nodes came from the .agents, .gemini, .kimi-code and .opencode trees monomind init writes. The scan now skips .agents, .gemini, .kimi-code, .opencode, .codex, its own .monograph cache and .mail by default, and inside a git work tree it only scans files git ls-files --cached --others --exclude-standard lists, so .gitignore is honoured (tracked files stay in even if they match; a .monographignore ! negation can still bring a file back; outside git the walk is unchanged). Anonymous closures (() => {, function () {) stay in the graph so calls inside them are still attributed to them, but monograph_query/search and god-node rankings no longer return them. @monoes/monograph 1.6.14.
  • monograph_impact and monograph_context no longer pick one of several same-named symbols (#405). Without a filePath both tools took whichever node named name came first, so asking about bridgeStoreEntry could land on a test mock and report "0 callers, Risk LOW" for a function with 29 call sites. When a name matches more than one definition they now return the candidates (non-test definitions first, with nodeId, file and line) and ask you to re-run with nodeId or filePath, like monograph_neighbors already did. Both tools take the new nodeId input, and filePath also accepts a trailing path fragment. The [MONOGRAPH_HINT] grep hint still picks the first match and is left for a follow-up.
  • monomind memory search finds matches with default options again (#407). The --threshold option defaulted to 0.7 while the memory bridge and the command's own fallback used 0.3, and correct matches from the bundled embedding model score about 0.55–0.61, so default searches returned nothing. The option default, the bridge and the sql.js fallback now share one DEFAULT_SEARCH_THRESHOLD (0.3).
  • monomind browse … exits as soon as its output is written (#408). Every browse subcommand left its CDP websocket open, so the process only ended at the CLI's 5 s force-exit watchdog: browse get title took ~5.5 s against 0.3 s through the bare monobrowse bin. The command now drops its CDP connection once the subcommand finishes (also when it fails), without touching the browser, so the next command still reuses the session; get title now takes ~0.3 s and open ~1.6 s instead of ~5.8 s. @monoes/monobrowse 1.0.28 exports disconnectSession() for this.
  • [MONOGRAPH_HINT]s now reach the model, and the status line stops showing an unmeasured "$ saved" (#409). The PreToolUse pre-search and pre-bash hooks printed their hints (and the graph-gate reminder) as plain stdout, which Claude Code only shows in the transcript, never to the model. They are now one JSON document, {"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":…}}; stdout stays empty when there is nothing to say and on any block, whose reason is still on stderr with exit code 2. Each hint was also credited as 1,700 saved tokens, which fed the status line's 💰 dollar figure and graph-status's "saved $". Hints no longer earn savings credit, and both displays show the hint count instead of dollars.
  • The fallback hook-handler's PreToolUse blocks now reach Claude Code (#446). The fallback hook-handler.cjs that init writes when the full helpers can't be copied ended with an unconditional process.exit(0), overriding the exit code 2 its graph gate sets to block a command. It now exits with process.exitCode, so a block's exit 2 survives.
  • Generated MCP configs start the version that ran init instead of monomind@latest (#419). .mcp.json, Codex config.toml, OpenCode opencode.json, Kimi mcp.json and the Antigravity/Gemini entries launched npx -y monomind@latest mcp start, which re-resolves the dist-tag on every start (3–4 s to tools/list), could hang past the client's startup timeout on a cold npx cache and leave _npx broken, and could switch versions mid-session. They now run npx -y --package=@monoes/monomindcli@<version> monomind mcp start, and the printed claude mcp add hints match. --pin latest or --no-pin keeps monomind@latest; --pin <version> still picks another version. monomind init --force re-pins after an upgrade; monomind update does not rewrite these configs. The Codex, OpenCode and Kimi entries also drop the unread MONOMIND_MODE, MONOMIND_HOOKS_ENABLED, MONOMIND_TOPOLOGY, MONOMIND_MAX_AGENTS and MONOMIND_MEMORY_BACKEND env vars (already gone from .mcp.json).
  • The per-prompt route hook is cheaper (#415). Opening the graph ran npm root -g (a 60–250 ms spawn) on every prompt in a project without its own @monoes/monograph; the answer is now cached for 24 h in ~/.monomind/cache/npm-root-g.json (or under MONOMIND_HOME), keyed by the node binary, npm_config_prefix and PATH, and asked again when the cached root is gone. A trivial reply ("ok", "yes", "continue", "thanks", fewer than three content words) now returns before any routing work — no pick, no graph, no Second Brain lookup, no banners — instead of only skipping the pick. The [PICK] line names an Org skill by its MCP call only: the (or: npx -y monomind org skills show …) suffix, ~40% of the line, is gone, since the picking section init writes into CLAUDE.md already gives that CLI fallback.
  • The CLAUDE.md init writes is 4 KB instead of 10.7 KB (#412). It is sent with every request and every subagent, and about 40% of it did not change what the model does in the project. The default (standard), minimal and solo templates drop the CLI command table, Monoswarm Rules, the topology/max-agents Project Config, the curated agent list, Memory Commands, Quick Setup, "Claude Code vs CLI Tools", Support, and the DDD / TDD-London / event-sourcing / "5-10+ todos" mandates; the opt-in full, security and performance templates keep their reference sections. Build & Test lists only the build, test and lint scripts package.json defines (with the detected package manager; the npm init placeholder test script does not count) and is left out when there are none. The Second Brain section appears only when the documents capability is active, and the agent picking rules only when the [PICK] prompt hook is installed. When a parent directory's CLAUDE.md already carries the monomind block, init in a subdirectory no longer writes a second copy and prints a warning naming that file. init --force over a pre-delimiter CLAUDE.md also replaces the retired sections instead of leaving them behind.
  • monomind init no longer installs docs as slash commands or --minimal as the full catalog (#411). Claude Code registers every .md under .claude/commands/ as a command, and its skill/command listing has a fixed budget past which descriptions are dropped. init now leaves out command-directory READMEs, _-prefixed includes and references/ pages (20 descriptionless entries); the task-file spec the mastermind commands read moved to .claude/skills/mastermind/references/taskfile.md, and the duplicate commands/mastermind/references/ copies are gone. --minimal installs 23 skills instead of 83: the mastermind engineering workflows (design, plan, execute, review, receive-review, debug, research, worktree) and the pieces they read, monolean, monodesign, stop-slop, verification-quality and the memory, GitHub and browser toolkits, plus the mastermind idea, org and memory skills the platform install always writes; the org-admin mastermind skills, monoswarm, hooks-automation and the rest are a new extended skill set, still part of the default install. The init wizard's Custom skill-set answer is now honoured (it left skills.all on, so every skill was installed) and no longer writes into the shared presets; it also offers the extended, browser and advanced sets. Agents marked deprecated: true are no longer installed, and the training/verify command groups, which never existed, are gone from the command map.
  • Agents, skills, commands and the guidance catalog only name MCP tools and CLI commands that exist (#421). Shipped markdown referenced 43 unregistered mcp__monomind__* tools 208 times per tree (swarm_init, memory_usage, coordination_orchestrate, hooks_pre_task, ...), the guidance catalog behind guidance_capabilities/guidance_recommend listed 30 tools and 15 commands that do not exist, and optimization agents told the model to run invented monomind topology-analyze-style commands. References now point at the real tool (monoswarm_init, monoswarm_memory, task_create, hooks_pre-task, monofence_scan, performance_bottleneck, ...) or are removed where nothing equivalent exists, and the catalog is rebuilt from the live registry. scripts/lint-tool-refs.mjs (pnpm run lint:tool-refs, run in CI) fails on any mcp__monomind__<tool> missing from the full MCP registry, any catalog tool or command that does not resolve, and any unresolved monomind <cmd> in an agent definition. The invented monomind github … / monomind actions … / monomind swarm … commands in six GitHub agents (140 references per tree) are still allowlisted in KNOWN_BAD_CLI_REFS; the allowlist can only shrink.
  • Session start no longer rebuilds the graph in non-git directories, and builds stop writing into the repo root (#414). Without a git HEAD the SessionStart freshen hook could never see the index as fresh, so every session started a full rebuild (a non-git workspace parent grew to 3.4 GB). The hook now skips directories outside a git work tree and prints a one-line hint to run monomind monograph build yourself, and it starts at most one automatic build per project every 10 minutes (tracked in .monomind/graph/last-auto-build). GRAPH_REPORT.md is now written to .monomind/GRAPH_REPORT.md instead of the repo root; monomind monograph build --report-path GRAPH_REPORT.md, MONOGRAPH_REPORT_PATH or buildAsync(..., { reportPath }) restore the old location. The churn cache moved from .monograph/cache/ to .monomind/cache/.
  • init no longer runs npm install @monoes/monograph in your project (#420). The code-graph step resolved @monoes/monograph/dist/src/index.js, which the package's exports map does not expose (ERR_PACKAGE_PATH_NOT_EXPORTED), so it always fell back to installing monograph into the user's project: a new dependencies entry in package.json and about 61 MB of node_modules. It now resolves the package's public entry from the CLI's own dependencies. The install fallback is gone; if monograph cannot be loaded, init prints one line saying to run npx monomind monograph build later.
  • init's summary counts the files it actually wrote (#420). It counted report items (a whole skill folder, an agent category) as files and labelled every skip and diagnostic "already exist", so an empty repo that received 2,060 files was told "267 created, 101 already exist". The counts now come from the disk, before and after the run, across the root files and every dot-directory init writes to (all platform trees): directories and files created, existing files updated, and existing files left unchanged.
  • monodesign detection no longer floods its output (#424). One failing token repeated on hundreds of elements printed one finding per element: doc/index.html gave 249 findings for 17 distinct issues, monodesign_detect returned about 41 KB, and design fix --dry-run printed nearly whole files. The text report now prints one line per (rule, snippet) with its count and up to three example locations (--no-group lists every occurrence; --json is unchanged). monodesign_detect returns the same groups, 20 at a time and most severe first, with rule descriptions listed once and a more hint that names the next offset; verbose: true returns the raw list. Contrast the static analyser cannot measure (translucent text or backgrounds, overlays, gradients, SVG text, or a page with no resolvable surface) is now reported as unverified and left out of the default count, with a line saying how many were held back (--include-unverified / include_unverified: true shows them). On doc/design-system.html that removes 99 of 102 contrast findings. fix --dry-run prints one hunk per edit with 3 lines of context instead of a single hunk from the first change to the last.
  • Opening the memory database no longer re-runs its dedupe repairs every time (#426). initializeSchema ran the namespace+key dedupe and the FTS5 duplicate-row cleanup on every open. Both scan every row, which made each knowledge_search or memory call wait seconds on a large store. They now run only while the database's PRAGMA user_version is below the schema version, which is now 4, so each existing store is repaired once more and then skips them. The namespace+key repair also runs whenever the unique index is missing, and an older release that opens the file writes its lower version back, so the next open repairs it again. On a synthetic 20k-entry, 507 MB store, a cold open fell from 3.0–4.5 s to about 10 ms.
  • Semantic search stays on brute force up to 100,000 entries (#426). The default MONOMIND_HNSW_THRESHOLD was 5,000. On the same 20k-entry store, the first search spent 78 s building the HNSW graph and wrote a 389 MB JSON cache, and later searches took 1.2 s to load that cache with about 1 GB peak RSS. Brute-force cosine answered in about 0.25 s at about 330 MB. The default is now 100,000, and setting the env var still overrides it.

Security

  • hooks_pre-command no longer rates destructive compound commands as safe (#399). The MCP tool capped any command starting with echo/ls/cat at low risk and git at 0.2, so echo hi && rm -rf ~/ and git push --force origin main returned shouldProceed: true while the PreToolUse Bash gate blocked them. It now splits the command on &&, ||, ;, |, & and newlines (quotes respected), checks every segment with no prefix caps, and applies the Bash gate's destructive patterns (mirrored, parity pinned by a test). Force-push to main/master, recursive rm of ~, $HOME or /, piping into a shell (curl … | sh, cat x | sh), dd of=/dev/…, mkfs and fork bombs are critical and shouldProceed: false; ls -la, git status and echo hi stay low.

npm: @monoes/memory@1.0.23, @monoes/monodesign@1.2.23, @monoes/monograph@1.6.15, @monoes/monobrowse@1.0.28, @monoes/monomindcli@2.19.0, monomind@2.19.0