Your agent just generated 200 lines of code. It looks clean. The types check out. But it imported a deprecated internal library, used any in three places your team banned six months ago, and created a utility function that already exists in your shared package. None of this will show up in CI. By the time a reviewer catches it, the PR has been open for two days and the developer has moved on.

Pre-commit hooks catch this at the moment it matters -before the code leaves the developer's machine. If you use cursor rules, claude code hooks, or a standalone hook framework, here's how to set them up for agent-generated code specifically.

Step 1: Install the hook framework

If you're not already using a hook manager, start with Husky (JavaScript/TypeScript) or pre-commit (Python). Both take under a minute to install.

# JavaScript / TypeScript projects
npm install --save-dev husky
npx husky init

# Python projects
pip install pre-commit
pre-commit install

This creates a .husky/ or .pre-commit-config.yaml at your project root. Every developer (and every agent running locally) will now trigger these hooks on git commit.

Step 2: Enforce coding standards with agent-specific checks

Standard linting catches standard problems. Agent code has its own failure modes. Add checks for the failure modes that matter most:

Banned patterns

Agents love to import things that technically work but your team has moved away from. Create a simple grep-based hook:

# .husky/pre-commit (or as a pre-commit hook script)
#!/bin/sh

# Check for banned imports
BANNED_PATTERNS=(
  "import.*from.*deprecated-utils"
  "require\(.*old-auth-lib\)"
  "from legacy_db import"
)

for pattern in "${BANNED_PATTERNS[@]}"; do
  if git diff --cached --name-only | xargs grep -l "$pattern" 2>/dev/null; then
    echo "BLOCKED: Found banned pattern: $pattern"
    exit 1
  fi
done

Keep this list in a shared file (.banned-patterns) so the team can update it without touching the hook script.

Duplicate detection

Agents frequently reinvent functions that already exist in your codebase. A lightweight check compares new function signatures against an index of existing utilities:

# Check for potential duplicates
NEW_FUNCTIONS=$(git diff --cached -U0 | grep "^+.*function\|^+.*const.*=.*=>" | sed 's/^+//')

if [ -n "$NEW_FUNCTIONS" ]; then
  echo "New functions detected. Verify these don't duplicate existing utilities:"
  echo "$NEW_FUNCTIONS"
  # In strict mode, compare against your function index
fi

This doesn't need to be a hard block -a warning is often enough to prompt the developer to check before committing.

Type strictness

Agents default to any when they're uncertain about types. If your team has a no-any policy, enforce it at commit time:

# Block 'any' type usage in TypeScript files
if git diff --cached --name-only -- '*.ts' '*.tsx' | xargs grep -n ': any' 2>/dev/null; then
  echo "BLOCKED: 'any' type usage detected. Use proper types."
  exit 1
fi

Step 3: Add rule context for your coding agent

Hooks that block code are useful, but hooks that teach the agent are better. When a hook fails, include enough context for the agent to fix the issue on retry:

echo "BLOCKED: Direct database imports detected in controller layer."
echo "FIX: Use the repository pattern. Import from src/repositories/ instead."
echo "EXAMPLE: import { UserRepository } from '@/repositories/user'"
exit 1

Agents parse error messages. If your hook output includes the fix, the agent will apply it on the next attempt without human intervention. This principle applies to cursor rules for teams and claude code hooks alike -clear, specific feedback beats vague "lint error" messages that force the agent into a guessing loop, wasting tokens and time.

Step 4: Connect to AI code policy enforcement

If you're using Uzera or a similar AI coding standards enforcement platform, your pre-commit hooks can pull rules directly from your rule set instead of maintaining separate .cursorrules files or hook scripts:

# Pull active rules and validate staged files
uzera check --staged --format=commit-hook

This keeps your hooks in sync with your team's evolving standards. When someone adds a new architectural rule in the dashboard, it's enforced at commit time the next day -no manual updates to .cursorrules examples or claude code hooks needed.

Step 5: Don't block everything

The temptation is to make every check a hard block. Resist it. Classify your checks by severity:

  • Hard block: Security issues, banned dependencies, direct database access from wrong layers. These should prevent the commit.
  • Warning: Potential duplicates, unusual patterns, missing tests. These print a message but allow the commit.
  • Info: Style suggestions, documentation reminders. These show up as notes.

Too many hard blocks and developers will start bypassing hooks entirely. The goal is to catch the things that matter -not to turn every commit into an interrogation.

What this buys you

A well-configured pre-commit setup adds 2-5 seconds to each commit. In exchange, you catch 60-70% of agent-generated issues before they ever reach a pull request. Reviewers spend their time on architecture and logic instead of asking "did you check if this utility already exists?"

Five minutes to set up. Hundreds of hours of review time saved over a quarter. Hard to argue with that.