Skip to content

Commit 8b44c1d

Browse files
committed
Make the Claude Code hook a single command
The hook no longer needs a script file. The formatter skips a file that is not Java by itself and exits with 0, so the filter the script carried was doing nothing, and the rest fits into the command of the settings block, in the shape of the auto-format example in the Claude Code documentation. The trailing `|| exit 2` stays for now: 2.98.0.1 exits with 1 on a file that does not parse, and only 2 makes Claude Code show the message to the model. The command was taken back out of the built page and run against the published 2.98.0.1 binary with simulated payloads, including a path with a space, and the timings quoted on the page were measured again.
1 parent 5686598 commit 8b44c1d

1 file changed

Lines changed: 9 additions & 25 deletions

File tree

‎docs/ai-agents.md‎

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -70,25 +70,7 @@ session. A `PostToolUse` hook on the `Edit` and `Write` tools runs after every f
7070
changes, and it gets the tool call as JSON on its standard input.
7171

7272
The hook needs `open-java-format` on the `PATH`, see [Command line](get-started/command-line.md),
73-
and [`jq`](https://jqlang.org/).
74-
75-
``` sh title=".claude/hooks/format-java.sh"
76-
#!/bin/sh
77-
# Claude Code runs this after every Edit and Write and passes the tool call as JSON on stdin.
78-
file=$(jq -r '.tool_input.file_path // empty')
79-
80-
case "$file" in
81-
*.java) ;;
82-
*) exit 0 ;;
83-
esac
84-
85-
# Exit code 2 makes Claude Code show the formatter's message to the model.
86-
open-java-format --ojf --skip-removing-unused-imports --replace "$file" || exit 2
87-
```
88-
89-
``` sh
90-
chmod +x .claude/hooks/format-java.sh
91-
```
73+
and [`jq`](https://jqlang.org/), which takes the path of the file out of that JSON.
9274

9375
``` json title=".claude/settings.json"
9476
{
@@ -99,8 +81,7 @@ chmod +x .claude/hooks/format-java.sh
9981
"hooks": [
10082
{
10183
"type": "command",
102-
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/format-java.sh",
103-
"args": []
84+
"command": "open-java-format --ojf --skip-removing-unused-imports --replace \"$(jq -r '.tool_input.file_path')\" || exit 2"
10485
}
10586
]
10687
}
@@ -109,17 +90,20 @@ chmod +x .claude/hooks/format-java.sh
10990
}
11091
```
11192

112-
Commit both files, and everyone who opens the project in Claude Code gets the hook. To keep it to
93+
Commit the file, and everyone who opens the project in Claude Code gets the hook. To keep it to
11394
yourself, put the `hooks` block into `.claude/settings.local.json` instead.
11495

96+
**Other files pass through.** The formatter skips a file that is not Java and exits with 0, so the
97+
hook needs no filter of its own.
98+
11599
**Unused imports stay for now.** An agent often adds an import in one edit and the code that uses
116100
it in the next. A full format after the first edit would delete that import, so the hook passes
117101
`--skip-removing-unused-imports`. The pre-commit hook and CI run the full check, and they catch the
118102
imports that really are unused.
119103

120-
**A file that does not parse goes back to the agent.** The formatter leaves the file as it is and
121-
prints the error. The script then exits with 2, the exit code that makes Claude Code show a hook's
122-
message to the model, so Claude sees it right after its edit:
104+
**A file that does not parse goes back to the agent.** The formatter leaves the file as it is,
105+
prints the error and exits with 1. `|| exit 2` turns that into 2, the exit code that makes Claude
106+
Code show a hook's message to the model, so Claude sees it right after its edit:
123107

124108
``` text
125109
src/main/java/com/example/Broken.java:5:22: error: ';' expected

0 commit comments

Comments
 (0)