While setting up Claude Code in my Ruby projects, I wanted RuboCop to run automatically whenever I created or edited a file. The CLAUDE.md instructions suggested simply telling Claude to run RuboCop, but I found this approach flaky. Sometimes it would skip files or not run corrections until I explicitly asked, and would often try to fix rubocop errors itself instead of running auto-correct
The Solution
Claude Code Hooks allow you to run scripts automatically on file events. Here is the hook I created to run RuboCop whenever a Ruby file is created or edited:
"hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "FILE_PATH=$(jq -r '.tool_input.file_path // empty'); if [[ \"$FILE_PATH\" =~ \\.(rb|rake)$|Rakefile$|Gemfile$ ]]; then echo \"Running RuboCop on $FILE_PATH\"; bundle exec rubocop --autocorrect \"$FILE_PATH\"; fi" } ] } ] }
How It Works
This configuration uses a PostToolUse hook that runs after Claude edits or writes a file. Here's what each part does:
- Event trigger (PostToolUse): Runs after Claude completes a tool action like editing or writing a file.
- matcher: "Edit|Write": Restricts the hook to only run after file edits or writes.
- Command breakdown:
FILE_PATH=$(jq -r '.tool_input.file_path // empty')
Extracts the edited file path from Claude’s tool input using jq.
if [[ "$FILE_PATH" =~ \.(rb|rake)$|Rakefile$|Gemfile$ ]]; then
Checks if the file has a Ruby-related extension (.rb, .rake) or is named Rakefile or Gemfile.
bundle exec rubocop --autocorrect "$FILE_PATH"
Prints a message indicating RuboCop is running and executes bundle exec rubocop --autocorrect on that file to format it immediately.
Notes
- -A applies both safe and unsafe corrections; I've opted for only safe corrections for now.
- Ensure bundle exec rubocop works in your environment. Adjust the command if you use a project-specific binstub.
- This setup enforces style guides consistently without needing manual intervention.
Conclusion
Using Claude Code Hooks like this keeps your codebase clean and saves time. You can find my full Gist here. If you integrate this into your workflow, I’d love to hear how it goes!