Skip to content

Commit 4f0e9c8

Browse files
committed
feat(hooks): add EditorConfig PostToolUse hook for Claude Code
Add the Claude Code hooks scaffolding (.claude/settings.json + README) and the first development hook: format-editorconfig.sh. After every Edit/Write/MultiEdit on a source file, it applies the project .editorconfig rules via `eclint fix`. eclint is an optional dependency: the hook skips silently when it is not installed (no global npm install side effect). Runs with `async: true` so formatting never blocks the conversation. Written in Bash; parses the hook payload with jq. First in a stack that adds one hook per PR for incremental review. Signed-off-by: Edmund Miller <edmund.miller@seqera.io>
1 parent 41a5f24 commit 4f0e9c8

3 files changed

Lines changed: 98 additions & 0 deletions

File tree

.claude/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Claude Code Hooks for Nextflow Development
2+
3+
This directory contains [Claude Code hooks](https://docs.claude.com/en/docs/claude-code/hooks)
4+
configured to improve the Nextflow development experience. Each hook is a small,
5+
self-contained Bash script under `hooks/`, wired up in `settings.json`.
6+
7+
Hooks are added incrementally — one per pull request — so each can be reviewed and
8+
understood on its own. This file documents the hooks that are currently wired up.
9+
10+
## Requirements
11+
12+
- [`jq`](https://jqlang.github.io/jq/) — hooks parse the Claude Code JSON payload with it.
13+
If `jq` is not on `PATH`, the hooks no-op silently.
14+
15+
## Hooks
16+
17+
### 1. EditorConfig enforcement (PostToolUse, async)
18+
- **Script**: `hooks/format-editorconfig.sh`
19+
- **Trigger**: after every `Edit`/`Write`/`MultiEdit` on a source file
20+
(`.groovy`, `.java`, `.gradle`, `.md`, `.txt`, `.yml`, `.yaml`, `.json`)
21+
- **Action**: applies `.editorconfig` rules with `eclint fix`
22+
- **Dependencies**: `eclint` (optional — install with `npm install -g eclint`; the hook
23+
skips silently if it is not present)
24+
- **`async: true`**: runs in the background so formatting never blocks the conversation
25+
26+
## Enabling / disabling
27+
28+
Hooks are configured in `.claude/settings.json`. Disable one by removing its entry;
29+
adjust timeouts there as needed.
30+
31+
## Troubleshooting
32+
33+
1. Ensure scripts are executable: `chmod +x .claude/hooks/*.sh`
34+
2. Verify `jq` is installed
35+
3. Inspect hook execution with `claude --debug` or the transcript (Ctrl-R)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env bash
2+
#
3+
# EditorConfig enforcement hook for Nextflow development.
4+
#
5+
# After an Edit/Write/MultiEdit, apply the project .editorconfig rules to the
6+
# edited source file with `eclint fix`. Non-blocking: warns on failure, never
7+
# stops Claude. Skips silently if eclint is not installed.
8+
#
9+
# Reads the Claude Code hook payload as JSON on stdin (requires `jq`).
10+
11+
set -uo pipefail
12+
13+
command -v jq >/dev/null 2>&1 || exit 0
14+
15+
input=$(cat)
16+
tool_name=$(jq -r '.tool_name // ""' <<<"$input")
17+
file_path=$(jq -r '.tool_input.file_path // ""' <<<"$input")
18+
19+
case "$tool_name" in
20+
Edit|Write|MultiEdit) ;;
21+
*) exit 0 ;;
22+
esac
23+
24+
[[ -n "$file_path" && -f "$file_path" ]] || exit 0
25+
26+
# Skip dot-directories (.git, .gradle, ...) and build outputs.
27+
case "$file_path" in
28+
*/build/*|*/.*/*) exit 0 ;;
29+
esac
30+
31+
# Only format known source extensions.
32+
case "$file_path" in
33+
*.groovy|*.java|*.gradle|*.md|*.txt|*.yml|*.yaml|*.json) ;;
34+
*) exit 0 ;;
35+
esac
36+
37+
# eclint is an optional dependency: skip quietly if it isn't installed.
38+
command -v eclint >/dev/null 2>&1 || exit 0
39+
40+
if out=$(eclint fix "$file_path" 2>&1); then
41+
jq -n --arg f "$(basename "$file_path")" \
42+
'{suppressOutput: true, systemMessage: ("✓ EditorConfig formatting applied to " + $f)}'
43+
else
44+
echo "Warning: eclint failed for $file_path: $out" >&2
45+
exit 1
46+
fi

.claude/settings.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"hooks": {
3+
"PostToolUse": [
4+
{
5+
"matcher": "Edit|Write|MultiEdit",
6+
"hooks": [
7+
{
8+
"type": "command",
9+
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format-editorconfig.sh",
10+
"timeout": 30,
11+
"async": true
12+
}
13+
]
14+
}
15+
]
16+
}
17+
}

0 commit comments

Comments
 (0)