DEV Community

Peter Tamas
Peter Tamas

Posted on

AI FIELD NOTES #002 – Weekly memos for Engineering Leaders

You are a software engineer, so you know that feeling. You are deep in dependency hell, reading library docs, digging through version histories, staring at compatibility matrices. Running tools to detect transitive version conflicts.

I got tired of it, too. So I asked Opus 4.6 to build a version checker hook and let AI deal with this problem instead of me. It turned out to be one of the most quietly impactful things I've added to my workflow.

At Bobcats Coding, we've deliberately built AI into our delivery system: how we specify, how we build, how we test, and how we learn. (Of course, if you are in the middle of a large legacy codebase with years of untouched dependencies, your mileage may vary, but that's a story for another time.:))

The core issue

One of my recurring frustrations with AI-generated code was debugging problems caused by poorly selected dependency versions. When you let AI add a dependency to a project, it usually does not install the latest version of the library. Instead, it often selects an artifact that is a few major versions behind the latest release. This behavior caused two types of issues for me repeatedly:

  1. Usage of already deprecated functions
  2. Version mismatch bugs

If you don’t have proper E2E tests in the project, version mismatch bugs can be very difficult to detect. The feature simply doesn’t behave as expected, usually without any error messages, which makes debugging extremely frustrating.

After running into this situation multiple times across several projects, I asked Opus 4.6 to create a version-checking script and integrated it into a PostToolUse hook, that:

  • checks whether all project dependencies are up to date (similar to Dependabot)
  • detects version mismatch issues

Since I started using this hook, I’ve never had to struggle with dependency versions again.

When AI adds a new dependency for a feature, even if I miss an E2E test for a particular scenario, this hook saves me a lot of time by catching hidden issues caused by version mismatches.

After every change in my dependencies, it runs version checks and automatically iterates on dependency versions until they align and all tests pass.

The fix

Ask AI to create a version-checker PostToolUse hook in projects that:

  • shows a warning when it detects a newer version of a dependency
  • checks for version mismatch issues and resolves them when found
  • detects transitive dependency conflicts and resolves them automatically

Best practices:

  • Update dependencies in a separate commit or PR when warnings appear to keep the project up to date.
  • Use TDD with BDD-style E2E tests (only partially related, but still helpful for catching subtle runtime issues).

Resulting Workflow

  1. AI adds dependencies during feature implementation
  2. The PostToolUse hook detects version issues
  3. The hook automatically aligns dependency versions
  4. Lint, type checks, and tests verify correctness
  5. Only stable commits enter the repository

Result:

  • Automated dependency version assurance
  • Reduced debugging time
  • Safer AI-generated code

What I learned

In my full-stack TypeScript projects, the hook works surprisingly well. Even when the updated major versions were not yet compatible with each other. The feedback loops in the project recognized this and automatically iterated with minor versions, reading issues and forums, and also automatically came up with a small, effective, temporary patch that solved the incompatibility issue.

The bottom line: connecting a version-checker pre-commit hook to all your projects isn't optional when you're working with AI-generated code. It's a mandatory feedback loop for maintaining developer productivity and saving a lot of my nerves.:)

Want to try it? Here is my implementation example

In my TypeScript projects, I implemented this workflow with a small script:

check-versions.ts

It performs:

  • dependency outdated checks
  • peer dependency mismatch detection
  • transitive conflict detection
  • optional automatic resolution

Example usage:

bun scripts/check-versions.ts              # All checks (pre-commit)
bun scripts/check-versions.ts --mismatch   # Mismatch only (fast)
bun scripts/check-versions.ts --fix        # Auto-resolve mismatches + transitive conflicts
bun scripts/check-versions.ts --json       # JSON output (for Claude hook)
Enter fullscreen mode Exit fullscreen mode

This allows different checks depending on the stage of the workflow.

For example, the fast mismatch-only check is ideal for pre-commit hooks.

An example output of the script:

bun scripts/check-versions.ts 2>&1)
  ⎿  ⚠ OUTDATED PACKAGES:
       @vitejs/plugin-react           4.7.0 → 5.1.4        ▲ major
       vite                           6.4.1 → 7.3.1        ▲ major
       @colyseus/schema               2.0.37 → 4.0.17      ▲ major
       colyseus.js                    0.15.28 → 0.16.22    ▲ minor
       @colyseus/ws-transport         0.15.3 → 0.17.9      ▲ minor
       colyseus                       0.15.57 → 0.17.8     ▲ minor
       @colyseus/testing              0.15.4 → 0.17.11     ▲ minor
       @biomejs/biome                 2.4.4 → 2.4.6        ▲ patch
       @storybook/react               10.2.13 → 10.2.16    ▲ patch
       @storybook/react-vite          10.2.13 → 10.2.16    ▲ patch
       storybook                      10.2.13 → 10.2.16    ▲ patch

     ✓ No version mismatches or transitive conflicts.
Enter fullscreen mode Exit fullscreen mode

The check-versions.sh hook

In the .claude/hooks folder, I created the check-versions.sh script, where I run the check-versions.ts script only when a package.json file is modified.

#!/usr/bin/env bash
# Version checker hook — runs after PostToolUse on Edit/Write.
# Only fires when the modified file is a package.json.
# Runs mismatch check and injects result into Claude's context.

set -euo pipefail

INPUT=$(cat)
ROOT="/Users/kond/kondfox/isuperhero-claude"

# Extract the file path from the hook payload
TOOL_INPUT=$(echo "$INPUT" | jq -r '.tool_input // empty' 2>/dev/null || true)
FILE_PATH=$(echo "$TOOL_INPUT" | jq -r '.file_path // empty' 2>/dev/null || true)

# Only run when a package.json was modified
if [[ -z "$FILE_PATH" ]] || [[ "$FILE_PATH" != *"package.json"* ]]; then
  exit 0
fi

# Run mismatch check only (fast, no network call)
cd "$ROOT"
RESULT=$(~/.bun/bin/bun scripts/check-versions.ts --mismatch --json 2>&1 || true)

echo "$RESULT"
Enter fullscreen mode Exit fullscreen mode

PostToolUse hook integration

In the .claude/settings.json I defined the PostToolsUse hook:

{
  // ...
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "/Users/kond/kondfox/isuperhero-claude/.claude/hooks/check-versions.sh"
          }
        ]
      }
    ],
  // ...
}
Enter fullscreen mode Exit fullscreen mode

Pre-commit Integration (Husky)

The script runs automatically before every commit via Husky.

Example pre-commit hook:

#!/usr/bin/env sh
cd"$(git rev-parse --show-toplevel)"

~/.bun/bin/bun scripts/check-versions.ts--fix
~/.bun/bin/bun run lint:fix
~/.bun/bin/bun run typecheck
~/.bun/bin/bun run test
~/.bun/bin/bun run test:e2e
Enter fullscreen mode Exit fullscreen mode

This ensures that:

  • dependency versions are aligned
  • lint errors are fixed
  • types compile
  • unit tests pass
  • E2E tests pass

before any commit enters the repository.

This creates a tight feedback loop for AI-generated code.

You can see a full working example here:

https://github.com/kondfox/isuperhero-claude

The repository contains the full check-versions.ts implementation and the Husky integration used in production.

Legacy project?

I have doubts about how good idea it is to integrate the version checker feedback loop into a legacy project where the dependencies are far behind the actual versions. But I’m gonna give it a try in such a project shortly, and share the result with you.

Top comments (0)