lint-on-save — Claude Code hook: lint after every edit
The hook fires a linter right after the agent changes a file. ESLint, Pylint or RuboCop runs on its own, no manual call needed.
npx claude-code-templates@latest --hook development-tools/lint-on-saveWhat lint-on-save does
It attaches to the PostToolUse event with the matcher Edit|MultiEdit. When Claude touches a file, the command reads the extension and picks a tool: npx eslint with --fix for .js, .ts, .jsx and .tsx, pylint for .py, rubocop --auto-correct for .rb. Linter failures are swallowed by 2>/dev/null || true, so a noisy warning never derails the agent.
The file path comes from $CLAUDE_TOOL_FILE_PATH. Anything outside those extensions falls through the if chain and nothing runs. There is no project-wide sweep either — only the file the agent just edited gets linted.
Worth adding if your project already has one of the three linters configured. ESLint goes through npx, so you need Node and the package installed locally, otherwise the command quietly does nothing. Same story for pylint and rubocop: both must be on your PATH.
What it helps with
- catch a style error right after a file edit
- stop running the linter by hand on every changed file
- auto-fix small JS and TS issues with
--fix - check Python files after the agent rewrites them
- keep Ruby code tidy without a separate pipeline step
Example prompts for the agent
- fix
src/utils.tsand let the linter run afterwards - rewrite
app/models/user.rb, the hook will call rubocop - edit
scripts/parse.pyand show me what pylint says
How to install lint-on-save
1claude-code-templates
npx claude-code-templates@latest --hook development-tools/lint-on-save2Manually: put the files in place
.claude/settings.jsonThe hooks block: event (PreToolUse, PostToolUse, Stop…) → command. Personal ones go to ~/.claude/settings.json
Step by step, with commands for each platform: Claude Code hooks: what they are, where to configure them, how to block a risky command
Questions about lint-on-save
How do I install lint-on-save in Claude?
Run npx claude-code-templates@latest --hook development-tools/lint-on-save, then check the entry in .claude/settings.json.
What does lint-on-save do?
After a file edit it runs the matching linter: ESLint for JS and TS, Pylint for Python, RuboCop for Ruby. Linter errors do not interrupt the agent.
Which files does the hook cover?
Only .js, .ts, .jsx, .tsx, .py and .rb. Other extensions are skipped because no branch of the condition matches.
Source text
lint-on-save.json · MIT
{
"description": "Automatically run linting tools after file modifications. Supports ESLint for JavaScript/TypeScript, Pylint for Python, and RuboCop for Ruby.",
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "if [[ \"$CLAUDE_TOOL_FILE_PATH\" == *.js || \"$CLAUDE_TOOL_FILE_PATH\" == *.ts || \"$CLAUDE_TOOL_FILE_PATH\" == *.jsx || \"$CLAUDE_TOOL_FILE_PATH\" == *.tsx ]]; then npx eslint \"$CLAUDE_TOOL_FILE_PATH\" --fix 2>/dev/null || true; elif [[ \"$CLAUDE_TOOL_FILE_PATH\" == *.py ]]; then pylint \"$CLAUDE_TOOL_FILE_PATH\" 2>/dev/null || true; elif [[ \"$CLAUDE_TOOL_FILE_PATH\" == *.rb ]]; then rubocop \"$CLAUDE_TOOL_FILE_PATH\" --auto-correct 2>/dev/null || true; fi"
}
]
}
]
}
}
© davila7 · MIT · davila7/claude-code-templates