Automatic ruff linting and formatting hook for Claude Code.
- ✅ Install once, use everywhere - Global installation works across all projects
- ✅ Automatic linting - Runs after every Python file edit in Claude Code
- ✅ Smart merging - Preserves existing Claude Code settings
- ✅ Zero configuration - Works out of the box
- ✅ Easy updates - Update once, all projects benefit
# Install the hook package (includes ruff automatically)
uv tool install ruff-claude-hook
# Verify installation
ruff-claude-hook checkNavigate to your Python project and run:
cd ~/my-python-project
ruff-claude-hook initThis creates or updates:
.claude/settings.json- Hook configuration.claude/settings.local.json- Permissions.claude/CLAUDE.md- Instructions for Claude
- Open your project in Claude Code
- Ask Claude to edit any Python file
- The hook runs automatically after each edit
- Claude sees the results and fixes any errors
You: "Add logging to api.py"
Claude: [Edits api.py]
✅ Ruff checks passed: api.py
Claude: "Added logging to api.py. All code quality checks passed."
If there are errors:
You: "Add a new function to utils.py"
Claude: [Edits utils.py]
❌ Ruff errors in utils.py:
utils.py:45:5: F841 Local variable 'result' is assigned to but never used
Claude: [Reads file, fixes the error, edits again]
✅ Ruff checks passed: utils.py
Claude: "Added the function. Fixed unused variable issue."
Customize ruff behavior in your project's pyproject.toml:
[tool.ruff]
line-length = 100 # Default: 88
[tool.ruff.lint]
select = ["E", "W", "F"] # Choose your rules
ignore = ["E501"] # Ignore specific rulesTo replace existing settings (creates backups):
ruff-claude-hook init --force# Update the hook package
uv tool upgrade ruff-claude-hook
# All projects automatically use the new version!# Initialize hook in current project
ruff-claude-hook init
# Force overwrite (with backup)
ruff-claude-hook init --force
# Verify installation
ruff-claude-hook check
# Show version
ruff-claude-hook --version
# Short alias for all commands
rch init
rch checkWhen Claude edits a Python file, the hook automatically:
- Auto-fix - Runs
ruff check --fixto fix common issues - Format - Runs
ruff formatto ensure PEP 8 compliance - Validate - Runs
ruff checkto verify no errors remain - Report - Shows results to Claude
If errors remain after auto-fixing, Claude will see them and fix them before continuing.
Global Installation:
~/.local/bin/ruff-claude-hook # Command installed here
Per-Project Setup:
my-project/
├── .claude/
│ ├── settings.json # Points to global command
│ ├── settings.local.json # Permissions
│ └── CLAUDE.md # Instructions for Claude
└── pyproject.toml # Ruff configuration (optional)
- Python 3.9+
- uv package manager
- Claude Code CLI
-
Verify installation:
ruff-claude-hook check
-
Check
.claude/settings.jsoncontains:{ "hooks": { "PostToolUse": [ { "matcher": "Edit", "hooks": [{"type": "command", "command": "ruff-claude-hook"}] } ] } } -
Check permissions in
.claude/settings.local.json:{ "permissions": { "allow": ["Bash(ruff-claude-hook:*)"] } }
The hook package includes ruff as a dependency, so it should be installed automatically. If you still get errors:
# Reinstall the hook package
uv tool uninstall ruff-claude-hook
uv tool install ruff-claude-hook
# Verify ruff is available
ruff --versionIf ruff-claude-hook init isn't merging with your existing settings:
# Use --force to replace (creates backups)
ruff-claude-hook init --force
# Then manually merge from backups:
.claude/settings.json.backup
.claude/settings.local.json.backup# Clone the repository
git clone https://github.com/your-username/ruff-claude-hook
cd ruff-claude-hook
# Install in development mode
uv tool install .
# Run tests
uv run pytest
# Install in a test project
cd /path/to/test-project
ruff-claude-hook initMIT License - see LICENSE file for details.
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request