Automation·terminal·MIT
catalyst-probes
Model judges over subagent dispatches, defined in TOML. Plus your own prompt rules.

catalyst-probes turns a TOML file into judges for Claude Code. Each [probe.<id>] table in ~/.claude/probes/probes.toml names a trigger, a model and an action; when a main-loop tool call matches, the mod sends the session so far to that model and acts on its one-line verdict, up to cancelling a subagent dispatch. [prompt.<id>] tables in the same file add text to a system prompt section, a tool description or a command description. It is the function-hooks part of Catalyst, the same author’s skills family for disciplined agentic development, and runs without it. Every consultation is a model call and costs tokens.
What it does
- judge, built in: reviews every
AgentandTaskcall from the main loop before it runs.OKorWARNlets it through;BLOCK,STOPorDENYcancels it with the model’s reason in the tool result. - idle-watch, built in: with no subagent running and
cooldown_min(30 by default) elapsed, asks the model whether to nudge you; aNUDGEverdict becomes a toast. - form, built in: no model call. It checks briefs, reports,
SendMessagetexts andgit commitorgit pushcommands against regular expressions from its table and can refuse the call. - Your own probes: one
[probe.<id>]table plus~/.claude/probes/<id>/prompt.md. A new id starts asact = "log_only";nudgeandcancelcome after you have read its journal.
Install
Needs Claude Code 2.1.270 or later (the floor stated in the plugin notes) with function hooks enabled, plus three variables in ~/.claude/settings.json.
claude plugin marketplace add TransmuteLabs/Catalyst
claude plugin install catalyst-probes@catalyst
The built-in probes are ports of “splices”, patches that the ContinuousClaude binary layer applies to the Claude Code executable. Each one arms in the mod only when its carrier variable says mod; otherwise the mod’s copy stays inert and the splice, if you have it, keeps running. You need the variables even if you never installed ContinuousClaude:
{
"env": {
"CLAUDE_JUDGE_CARRIER": "mod",
"CLAUDE_FORM_CARRIER": "mod",
"CLAUDE_IDLE_CARRIER": "mod",
"CLAUDE_JUDGE": "1"
}
}
CLAUDE_JUDGE and CLAUDE_IDLE are off when empty; CLAUDE_JUDGE=enforce makes a blocking verdict binding whatever the table says. CLAUDE_FORM, CLAUDE_PROBES (your own ids) and CLAUDE_PROMPTS (the prompt layer) are on when empty and off with 0, off or false. Add tables, run /reload-plugins and look for hooks module catalyst-probes loaded in the debug log; the author counts that line as acceptance, not a green claude plugin validate.
A minimal consultant, paired with ~/.claude/probes/brief-check/prompt.md:
[probe.brief-check]
enabled = true
act = "log_only"
rx = "OK|WARN|BLOCK"
models = ["glm-5.3"]
cooldown_min = 60
[probe.brief-check.when]
field = "tool"
in = ["Agent", "Task"]
How it works
The mod hooks tool.call for the main loop only; subagent calls pass through untouched. It reads probes.toml from the global home (~/.claude/probes/, $CLAUDE_CONFIG_DIR/probes or CLAUDE_PROBES_DIR) and from the nearest .claude/probes/probes.toml above the working directory, project keys winning; a project can switch a built-in off with enabled = false. The when predicate (equals, in, matches, count_below, older_than_min and a few more, combinable with all, any and not) tests the tool name, the subagent type, the dispatch prompt, the number of live agents from $.agent.list() and the time of the probe’s last consultation. A custom probe without when never fires.
A consultation is one $.model.complete call per rung of the models ladder until a reply starts with a word from rx (glm-5.3 when no model is set; CLAUDE_JUDGE_MODEL overrides it for the judge). The prompt is <id>/prompt.md (a project’s copy replaces it, prompt.extra.md is appended), then the transcript from $.session.messages() clipped to the last context_chars (24,000 by default, each message cut at 2,000), then for the judge the dispatch itself: tool, subagent type, model and up to 16,000 characters of its prompt. attach_files adds .md and .txt files named in that prompt, up to 90,000 characters. Each consultation therefore costs about the size of your recent transcript plus a reply of up to max_tokens (8,000 by default).
act = "cancel" waits for the verdict before the tool runs; log_only and nudge consult in the background, capped at eight by a counter in the plugin store. Verdicts of cancel probes are memoised by tool, agent and a hash of the prompt, so an identical retry gets the same answer without a new call; the coaching text the mod appends to the communication:L section of the system prompt tells the model to change the dispatch rather than repeat it. If no rung answers, the judge denies (fail_closed is true only for it) and other probes let the call through.
Everything lands under the global probes home: <id>/records/mod-<tool_use_id>.json is the full record of a consultation, including the first 2,000 characters of the raw reply (record = false skips it), and <id>/journal.jsonl.shard.* is one index line per record. Prompt rules that apply write prompts/records/applied-<id>.json. The mod makes no network calls of its own; the model call goes through Claude Code.
Prompt rules fire on prompt.section, tool.describe and command.describe. A rule names one target, a mode (append, prepend or replace), its text inline or from <home>/prompts/<text_file>, and optionally when_env with one of the five variables above (any other name refuses the rule). Measured by the author on 2.1.267: 26 sections, 24 tool descriptions and 254 command descriptions in the main loop. A subagent’s system prompt carries one section, so a section rule never reaches it; a tool rule reaches every agent that holds that tool.
Limitations
- Main loop only. Subagent tool calls are not judged, and the
subagentskey in a table does not change that in 0.1.6. - The
formprobe needs about thirty regular-expression keys in[probe.form](brief_path,fence,git_msgand so on) and stays silent without all of them. The plugin’s notes do not list them; they point to a kit that is not in the repo. - A
cancelconsultation has to finish inside the host’s 10 second hook budget, which the mod cannot raise; settimeout_msper rung with that in mind. - The reach figures date from 2.1.267 and have not been re-measured since the floor moved to 2.1.270.
More mods
The whole directory →autodev-core
Autonomous sprint loop: brainstorm, auto, iterate, audit, review, ship. Redacts secrets.
claude plugin install autodev-core@autodevcdx
Codex and Antigravity as detached lanes, driven with 21 tools from the session.
cdx doctor --probeagent-flow
Every subagent of the session in a live tree beside the transcript. Zero tokens.
claude plugin install agent-flow@claude-agent-flowanchorwatch-mod
Blocks rm -rf, force pushes, DROP TABLE, curl | sh and cat .env before they run.
claude --plugin-dir ./anchorwatch/plugins/anchorwatch-mod