HookStackGitHub
Back to catalogue
ValidationPreToolUse· BashPreToolUseBefore tool execution · can block⚡ blocking

Enforce uv for Python dependencies

Blocks pip install, pip3 install and poetry add/install commands and redirects the agent to the uv equivalent. Prevents virtual environment fragmentation.

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

Providers & tags

Claude Code
#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
import { readFileSync } from 'fs';

const input = JSON.parse(readFileSync(0, 'utf8'));
if (input.tool_name !== 'Bash') process.exit(0);

const cmd = input.tool_input?.command ?? '';

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' },
];

const hit = BLOCKED.find(({ re }) => re.test(cmd));
if (hit) {
  process.stdout.write(JSON.stringify({
    decision: 'block',
    reason: `Use '${hit.fix}' instead — this project manages dependencies with uv.`,
  }));
}