Back to catalogue
ValidationPostToolUse· Write|EditPostToolUseAfter tool execution · non-blocking· non-blocking
Ruff format after write
Python lands PEP 8-clean on every save
After every Python file write or edit, runs ruff format via uv to apply consistent style without any agent intervention.
What does the Ruff format after write hook do?
Ruff format after write is a Claude Code PostToolUse hook matching Write|Edit. It fires automatically at that lifecycle event — outside the model, so it can't be skipped or forgotten. Python lands PEP 8-clean on every save.
Use cases
- PEP 8 compliance without thinking about it
- Consistent formatting across a team
- Reduced review noise on style changes
Tags
#validation#ruff#format#python#quality
settings.json fragment
{
"hooks": {
"PostToolUse": [
{
"hooks": [
{
"command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/ruff-format.mjs",
"type": "command"
}
],
"matcher": "Write|Edit"
}
]
}
}Script · .claude/hooks/ruff-format.mjs
#!/usr/bin/env node
// Formate le fichier Python avec ruff après écriture (PostToolUse Write|Edit)
import { readFileSync } from 'fs';
import { execSync } from 'child_process';
import { fileURLToPath } from 'url';
function defaultExec(cmd) {
execSync(cmd, { stdio: 'ignore', timeout: 15_000 });
}
export function run(input, { exec = defaultExec } = {}) {
const filePath = input.tool_input?.file_path ?? input.tool_input?.path ?? '';
if (!filePath.endsWith('.py')) return null;
try {
exec(`uv run ruff format "${filePath}"`);
return null;
} catch {
// uv/ruff absent — non bloquant
return null;
}
}
/* v8 ignore next 4 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const input = JSON.parse(readFileSync(0, 'utf8'));
run(input);
}