Back to catalogue
ValidationPreToolUse· BashPreToolUseBefore tool execution · can block⚡ blocking
Enforce uv for Python dependencies
Forces uv, ends pip/poetry drift
Blocks pip install, pip3 install and poetry add/install commands and redirects the agent to the uv equivalent. Prevents virtual environment fragmentation.
What does the Enforce uv for Python dependencies hook do?
Enforce uv for Python dependencies is a Claude Code PreToolUse hook matching Bash. It fires automatically at that lifecycle event — outside the model, so it can't be skipped or forgotten. Forces uv, ends pip/poetry drift.
Use cases
- Keep dependency management consistent on a uv-based project
- Avoid pip/uv conflicts in the same virtualenv
- Enforce team tooling conventions without having to remind the agent
Tags
#validation#uv#pip#poetry#python#package-manager
settings.json fragment
{
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/enforce-uv.mjs",
"type": "command"
}
],
"matcher": "Bash"
}
]
}
}Script · .claude/hooks/enforce-uv.mjs
#!/usr/bin/env node
// Bloque pip/poetry install et suggère l'équivalent uv (PreToolUse Bash)
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';
const BLOCKED = [
{ re: /(^|[;&|\s`])pip\s+install\b/, fix: 'uv add' },
{ re: /(^|[;&|\s`])pip3\s+install\b/, fix: 'uv add' },
{ re: /(^|[;&|\s`])poetry\s+add\b/, fix: 'uv add' },
{ re: /(^|[;&|\s`])poetry\s+install\b/, fix: 'uv sync' },
];
export function run(input) {
if (input.tool_name !== 'Bash') return null;
const cmd = input.tool_input?.command ?? '';
const hit = BLOCKED.find(({ re }) => re.test(cmd));
if (!hit) return null;
return {
decision: 'block',
reason: `Use '${hit.fix}' instead — this project manages dependencies with uv.`,
};
}
/* v8 ignore next 5 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const input = JSON.parse(readFileSync(0, 'utf8'));
const result = run(input);
if (result) process.stdout.write(JSON.stringify(result));
}