feat: catch-all router primitives + explore recipe skeleton#7
Merged
HeinrichvH merged 1 commit intomainfrom Apr 22, 2026
Merged
feat: catch-all router primitives + explore recipe skeleton#7HeinrichvH merged 1 commit intomainfrom
HeinrichvH merged 1 commit intomainfrom
Conversation
Enables a single `"matcher": "*"` entry in Claude Code's settings.json to route *every* tool call through Exactor, with per-rule intercept/skip logic living in `.exactor.yml` instead of duplicated across Claude config and Exactor config. Richer rule primitives + hard fail-open contract so catch-all doesn't turn a config typo into a session-wide block. ## Fail-open contract Under a catch-all matcher, any unexpected error in this hook blocks every tool call. `pre_tool_use` / `post_tool_use` now wrap their bodies in an outer try/except — on any exception (malformed stdin, missing worker, YAML parse error, runtime surprise) they log to stderr and exit 0 so the raw tool runs. Also validates `route_to` against defined workers at config-load time so misconfigs surface via `exactor check` rather than at tool-fire time. Runtime re-checks worker existence as belt-and-braces. Six new tests pin the contract: unmatched tool, missing config, malformed stdin, malformed YAML, load-time validation, runtime ghost-worker. ## query_template New `InterceptRule.query_template` field — Python str.format-style template that interpolates multiple tool_input fields into one query. Lets Grep intercepts fold pattern + path + glob into a natural-language question for a code-exploration subagent, instead of losing scope by picking just one field. Missing keys render as empty string via a SafeDict so optional fields don't raise. Takes precedence over query_field when both are set. ## unless_match New `InterceptRule.unless_match` field — regex on the templated query; rule is skipped if it matches. Symmetric with existing `match`, more flexible than the named `unless` predicates for query-shape heuristics (e.g. "skip trivially short patterns"). Both named `unless` and `unless_match` can coexist on the same rule. ## CLI default subcommand `exactor hook` (no subcommand) now defaults to `event=pre`. Older docs suggested the bare form, and a catch-all matcher exposes argparse failures as blocking hook errors on every tool call. Explicit forms (`exactor hook pre`, `exactor hook post`) continue to work unchanged. ## recipes/explore/ Skeleton recipe documenting the shape for routing Grep / Glob (and optionally Read) to a code-search subagent. Ships with commented intercept rules, sensible defaults (`cache: false` — code changes under us), and a README explaining the contract (`explore` CLI takes one positional query arg, prints a cited report to stdout). Users bring their own subagent (Goose, Aider, Claude API, etc.). ## Tests 57 passing, +14 new (fail-open x6, query_template x5, unless_match x2, cli-default x1). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Enables a single
"matcher": "*"entry in Claude Code's settings.json to route every tool call through Exactor, with per-rule intercept/skip logic living in.exactor.ymlinstead of duplicated across Claude config and Exactor config. Richer rule primitives + hard fail-open contract so catch-all doesn't turn a config typo into a session-wide block.Fail-open contract
Under a catch-all matcher, any unexpected error in this hook blocks every tool call.
pre_tool_use/post_tool_usenow wrap their bodies in an outer try/except — on any exception (malformed stdin, missing worker, YAML parse error, runtime surprise) they log to stderr and exit 0 so the raw tool runs. Also validatesroute_toagainst defined workers at config-load time so misconfigs surface viaexactor checkrather than at tool-fire time. Runtime re-checks worker existence as belt-and-braces. Six new tests pin the contract: unmatched tool, missing config, malformed stdin, malformed YAML, load-time validation, runtime ghost-worker.query_template
New
InterceptRule.query_templatefield — Python str.format-style template that interpolates multiple tool_input fields into one query. Lets Grep intercepts fold pattern + path + glob into a natural-language question for a code-exploration subagent, instead of losing scope by picking just one field. Missing keys render as empty string via a SafeDict so optional fields don't raise. Takes precedence over query_field when both are set.unless_match
New
InterceptRule.unless_matchfield — regex on the templated query; rule is skipped if it matches. Symmetric with existingmatch, more flexible than the namedunlesspredicates for query-shape heuristics (e.g. "skip trivially short patterns"). Both namedunlessandunless_matchcan coexist on the same rule.CLI default subcommand
exactor hook(no subcommand) now defaults toevent=pre. Older docs suggested the bare form, and a catch-all matcher exposes argparse failures as blocking hook errors on every tool call. Explicit forms (exactor hook pre,exactor hook post) continue to work unchanged.recipes/explore/
Skeleton recipe documenting the shape for routing Grep / Glob (and optionally Read) to a code-search subagent. Ships with commented intercept rules, sensible defaults (
cache: false— code changes under us), and a README explaining the contract (exploreCLI takes one positional query arg, prints a cited report to stdout). Users bring their own subagent (Goose, Aider, Claude API, etc.).Tests
57 passing, +14 new (fail-open x6, query_template x5, unless_match x2, cli-default x1).