Skip to content

docs(hookify): refresh authoring cheatsheet + add regression harness#10

Merged
adelaidasofia merged 1 commit intomainfrom
fix/hookify-authoring-docs-and-test-harness
May 4, 2026
Merged

docs(hookify): refresh authoring cheatsheet + add regression harness#10
adelaidasofia merged 1 commit intomainfrom
fix/hookify-authoring-docs-and-test-harness

Conversation

@adelaidasofia
Copy link
Copy Markdown
Owner

Summary

The hookify authoring docs were authored against an older hookify plugin with two known bugs that have since been fixed upstream in anthropics/claude-code#54873. This refreshes the cheatsheet, codifies three additional gotchas surfaced during a recent rule audit, and ships a regression harness so users can catch the same class of bugs at authoring time instead of at runtime.

What changes

  • `templates/rules/hookify-authoring.md`: rewrite

    • The `new_text` field note is updated. Older hookify returned empty for `new_text` on Write; the upstream fix makes it fall back to `tool_input.content`, so it now works on both Write and Edit. Single-quoting workaround is removed.
    • The YAML double-escape note is updated. The original docs described it as a YAML feature, but it was actually a hand-rolled parser stripping escape sequences incorrectly. With `yaml.safe_load` upstream, double-quoted patterns work, though single quotes are still preferred for readability.
    • New section: negative lookahead with `re.search` requires `^` anchor. A pattern like `(?!.*/Archive/).foo` does NOT exclude Archive paths, because `re.search()` can skip the lookahead and match later. `^(?!./Archive/).*foo` is the fix.
    • New section: unquoted patterns starting with `[` or `\\` break YAML. `pattern: [A-Z]` is a flow sequence; `pattern: \\[owner\\]` errors on the bare backslash. Both drop the rule silently at load time.
    • New section: companion PreToolUse Python hooks for logic beyond regex, including the constraint that MCP tools cannot be called from a hook subprocess (the MCP server runs in the parent Claude process). Pattern: read the underlying config file directly instead.
  • `templates/scripts/hookify-rule-tests.py`: new file

    • Copy-then-edit regression harness. Pipes `(rule_name, tool_type, path, content, expect_fire, label)` tuples through the hookify subprocess and asserts each rule fires or stays silent as expected. Exit 0 means all pass.
    • Catches three bug classes: non-existent operators (silent always-False), YAML parse errors that drop a rule at load time, and pattern regressions after a rule edit.
    • VAULT_ROOT and HOOKIFY_PRETOOLUSE_PATH are configurable via env vars or constants at the top of the file.
  • `templates/hookify-rules/README.md`: link to both the cheatsheet and the harness.

Test plan

  • Run the new harness against an installed hookify plugin (with the upstream fix from #54873): 4/4 pass.
  • Verify the cheatsheet's example regex patterns parse cleanly under `yaml.safe_load`.
  • Cheatsheet's negative-lookahead-with-anchor example tested manually with `re.search` (matches without `^` anchor incorrectly succeed; with anchor they correctly fail).
  • No personal data in the diff (word-boundary scrub clean).

🤖 Generated with Claude Code

The hookify-authoring template was authored against an older hookify
plugin that had two known bugs (now fixed upstream in claude-code#54873):

1. `new_text` field returned empty on Write tool calls. The cheatsheet
   recommended `content` as a workaround. With the upstream fix,
   `new_text` falls back to `tool_input.content` and works correctly,
   so the workaround note is no longer accurate.

2. The hand-rolled YAML parser in core/config_loader.py double-escaped
   backslashes, which made double-quoted regex patterns load with extra
   backslashes (`"\d"` stored as `\\d`). The cheatsheet documented this
   as a YAML feature ("double-quoted strings double-escape backslashes")
   and recommended single-quoting as the workaround. With yaml.safe_load
   in place upstream, double-quoted patterns work correctly. Single
   quotes are still preferred for readability, but the underlying bug
   is gone.

This commit:

- Updates `templates/rules/hookify-authoring.md` to reflect the post-fix
  reality and adds three new sections that codify additional gotchas
  surfaced during a recent rule audit:
    * Negative lookahead with `re.search` requires `^` anchor
    * Unquoted patterns starting with `[` or `\` break YAML parsing
      (the parser reads `[A-Z]` as a flow sequence and errors on bare
      backslash, dropping the rule at load time)
    * Companion PreToolUse Python hooks for logic that goes beyond
      regex, including the constraint that MCP tools cannot be called
      from a hook subprocess (replicate by reading config files
      directly instead)

- Adds `templates/scripts/hookify-rule-tests.py`, a copy-then-edit
  regression harness that pipes synthetic tool_input payloads through
  the hookify subprocess and asserts each rule fires (or stays silent)
  as expected. Exit 0 means all pass. Catches three bug classes at
  authoring time:
    1. Rule references a non-existent operator (silent always-False)
    2. YAML parse error drops a rule at load time
    3. Pattern logic regression after a rule edit

  The harness is dogfooded: this PR's template tests pass against a
  vault running the patched hookify plugin.

- Adds entries to `templates/hookify-rules/README.md` linking to both
  the authoring cheatsheet and the harness.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@adelaidasofia adelaidasofia merged commit c13a239 into main May 4, 2026
6 checks passed
@adelaidasofia adelaidasofia deleted the fix/hookify-authoring-docs-and-test-harness branch May 4, 2026 02:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant