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.

hooks3matcherregex2validation5antigravity437measurement8

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 90-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-07-11
Are You Actually Using Every Permission You Granted? Tightening Antigravity's Unified Permissions from Real Usage Logs
Once you flip a unified permission policy to 'allow everything,' unused grants quietly pile up. This is the grant-to-usage reconciliation loop: match granted permissions against your action logs, revoke what was never exercised, and narrow what's too broad — with working TypeScript and real numbers from solo operation.
Antigravity2026-07-07
Before Your Finger Learns the Approval Dialog: Folding Antigravity Permissions Into One Policy
Scattered approval dialogs, per-MCP allowlists, repeated re-auth. Built around Antigravity 2.2.1's unified permissions and OAuth keyring storage, here is how I fold every permission into a single policy and design away approval fatigue, with working code and measured numbers.
Antigravity2026-07-02
Parallel Agents Multiply Artifacts Too — Designing Lifespans and Cleanup for Intermediate Outputs
Worktrees, screenshots, temp branches — parallel agents leave debris at parallel speed. A design for defining artifact lifespans and automating cleanup without ever destroying uncommitted work.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →