◉ANTIGRAVITY LABJP
Articles/Antigravity Basics
◉ Antigravity Basics/2026-08-09Advanced

The Hooks That Get Rejected Are the Cheap Ones: Measuring Matcher Reachability

Hook configurations that can never execute are now rejected at load time. But when I checked my own config against all 21 tool names, the real problems were on the side that passed. A static reachability checker, plus measured numbers on what over-matching actually costs.

hooks6matcherregexvalidation5antigravity472measurement8

✦ Premium Article

Formatting was supposed to run on every save. It wasn't running.

No error. Nothing in the logs. The hook was registered, the config file said exactly what I meant it to say. It simply never fired.

IDE 2.6.0 started rejecting hook configurations that can never execute, with a clear error at load time instead of silently ignoring them. That is a genuine improvement, and I took it as a prompt to audit everything I had.

The audit hurt. Just not on the side that got rejected.

There are two kinds of hooks that don't work

The first kind never fires. The matcher hits no tool name, the event is misspelled, the command isn't on PATH. Load-time rejection catches roughly this family.

The second kind fires too much. Nothing about it is broken — the regex compiles, the command exists, the hook runs happily. It just also runs on tools the author never had in mind.

The first kind silently does nothing. The second kind silently does something. The second one is clearly the worse neighbor.

So I measured mine.

Cross-checking matchers against every tool name

Whether a matcher hits anything is not a property of the matcher. It's a property of the matcher paired with the set of tool names it will be tested against.

I wrote out the 21 tool names that actually appear in my sessions — the built-ins plus the names my connected MCP servers expose, like mcp__github__create_issue.

Then I took the matchers I and the developers around me actually write, and tested each one under both semantics: substring matching (re.search) and full matching (re.fullmatch).

matcherstatussubstringfull matchdelta
"" (empty)ok21021
*compile error———
.*ok21210
Bashok211
Editok312
Write|Editok523
^Bash$ok110
Bash.*ok220
mcp__.*ok550
Read|Glob|Grepok330
Notebookok101
editok000
(Write|Editcompile error———

Of the 12 that compiled, 5 — 41.7% — changed how many tools they hit when the semantics changed.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦An empty matcher hits all 21 tools under substring semantics and zero tools under full-match semantics — the same empty string flips meaning depending on the engine
✦A dead hook costs 0ms because it never runs. The expensive class is over-matching, which passes validation cleanly and adds 31.6ms per unintended tool call with a Node hook
✦A 126-line checker for reachability, event names, and command resolution in hooks.json — 48.28ms of check time even at 1,000 groups, small enough for a CI step
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

◉ Antigravity2026-10-24
The File Is Right There, but Linux Says "No Such File" — Check the Interpreter, Not the Path
When agy's grep search fails on Linux and the log says "no such file or directory" for a file that clearly exists, the culprit is the ELF interpreter. Here is how to confirm it, reproduce it, and work around it for now.
◉ Antigravity2026-10-20
NoClassDefFoundError on Old Android Devices Only — Four Clues I Gather Before Handing It to an Agent
Everything works on new phones, but Android 6 devices crash. Using a Supplier NoClassDefFoundError that appeared after a Glide update, this note covers the order of diagnosis, the coreLibraryDesugaring setup, and what to prepare before asking an agent to investigate.
◉ Antigravity2026-10-17
Build the Environment Note Before You Write the Question — A Small Shell Script for Posts That Get Replies
A small shell script that gathers your OS, tool versions, and the tail of a log into one note you can paste into a forum post or issue, with secrets masked. Here is what it catches, what it misses, and the three lines only you can write.