fix(hooks): Parse Claude Code's nested tool_input payload - #114
Merged
Conversation
Closes #110. parseHookFilePathsErr handled a top-level file_path and Codex's tool_input.command, but not tool_input.file_path — the shape Claude Code actually sends for Edit and Write. The regex fallback that would have caught it only runs when json.Unmarshal fails, so a well-formed payload in the unhandled shape was the one case that silently matched nothing and returned no paths. Two features depended on that parse and have therefore been inert on Claude Code: - Agent-edit provenance never recorded, so .codemap/agent_edits.jsonl was never created and the working-set summary always fell back to disk churn — the exact conflation the feature was built to remove. - The post-edit blast-radius report never fired, which is the behavior CLAUDE.md instructs agents to rely on after editing. Verified against the release binary before and after with the payload Claude Code sends: previously no output and no record; now the hub report prints and the edit is recorded. Also accepts tool_input.notebook_path for NotebookEdit. Tests cover each payload shape end to end rather than only the parser, since the parser was arguably correct — it simply never saw the shape it needed. Docs updated now that the behavior works: HOOKS.md describes working-set provenance and the payload keys it depends on, notes doctor's scope fallback from #100, and marks post-edit as recording provenance. The manual hook JSON keeps the bare PATH form, which is correct for hand-managed settings and accepted by doctor since #100. Drive-by: CONTRIBUTING suggested Elixir and Scala as languages to add, both already supported; plugin README said "skill" singular but ships two. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Fixes the PostToolUse hook path extraction so Claude Code payloads for Edit/Write/NotebookEdit are correctly recognized, restoring agent-edit provenance recording and the post-edit blast-radius reporting that depends on it.
Changes:
- Extend hook payload parsing to accept
tool_input.file_pathandtool_input.notebook_pathin addition to the existing legacy and Codex shapes. - Add end-to-end and parser-level tests covering multiple host payload shapes, including a regression test that drives
hookPostEdit. - Update hook and contribution documentation to reflect the now-working provenance behavior and current project state.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| plugins/codemap/README.md | Fix wording to reflect multiple shipped skills. |
| docs/HOOKS.md | Document provenance-based working set behavior and clarify doctor scope fallback behavior. |
| CONTRIBUTING.md | Update example “languages to add” list to avoid listing already-supported languages. |
| cmd/hooks.go | Parse nested tool_input.file_path / tool_input.notebook_path for Claude Code hook payloads. |
| cmd/hooks_payload_test.go | Add regression tests for supported payload shapes and nested provenance recording. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+1816
to
1819
| // Legacy shape: some hosts put the path at the top level. | ||
| if filePath, ok := data["file_path"].(string); ok { | ||
| return []string{filePath}, nil | ||
| } |
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.
Closes #110.
The bug
parseHookFilePathsErrhandled a top-levelfile_pathand Codex'stool_input.command, but nottool_input.file_path— the shape Claude Code actually sends forEditandWrite.The regex fallback that would have caught it only runs when
json.Unmarshalfails. A well-formed payload in the unhandled shape parses cleanly, matches nothing, and returns no paths — so the hook returned early and did nothing, silently.Same file, same hook, before this change:
After:
Impact
Two features were inert on Claude Code:
.codemap/agent_edits.jsonlwas never created, so the working-set summary always fell back to disk churn. That conflation is precisely what the feature was built to remove. Across a four-day session in this repo with a dozen-plusEdit/Writecalls and four merged PRs, the file never appeared.CLAUDE.mdtells agents to rely on.Also now accepts
tool_input.notebook_pathforNotebookEdit.Tests
Six payload shapes, covered end to end rather than only at the parser — the parser was arguably correct, it just never saw the shape it needed, so a parser-only test would have passed while the feature stayed broken:
file_pathtool_input.file_path(Edit)tool_input.file_path(Write)tool_input.notebook_path(NotebookEdit)tool_input.command(Codexapply_patch)tool_input.command(Bash, no path)Plus
TestHookPostEditRecordsAgentEditForNestedPayload, which driveshookPostEditand asserts the record lands.Docs
Updated now that the behavior actually works, rather than documenting the broken state:
docs/HOOKS.md— describes working-set provenance and the payload keys it depends on; notes doctor's project→user scope fallback from fix(doctor): Report effective agent config, not file layout #100; the post-edit row now mentions provenance.CONTRIBUTING.mdoffered Elixir and Scala as languages "to add" (both shipped);plugins/codemap/README.mdsaid "skill" singular but ships two.Type of change
Verification
go test ./...,go vet,staticcheck,gofmtclean;go vetclean cross-compiled for windows/amd64 and linux/amd64. Behavior confirmed against a built binary with the exact payload Claude Code emits.