HookStackGitHub
Back to catalogue
WorkflowSessionStartSessionStartOn Claude Code session start· non-blocking

Dependency check and install at startup

Checks for the required system tools and automatically installs the project dependencies (npm ci, uv sync) at session startup.

Use cases

  • Environment always ready as soon as a session opens
  • Automatic onboarding on a new project

Providers & tags

Claude Code
#setup#dependencies#onboarding#npm#uv#install

settings.json fragment

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/setup-check-deps.mjs",
            "type": "command"
          }
        ],
        "matcher": ""
      }
    ]
  }
}

Script · .claude/hooks/setup-check-deps.mjs

#!/usr/bin/env node
// Vérifie que les dépendances du projet sont à jour au démarrage de session (SessionStart)
import { existsSync, statSync } from 'fs';
import { join } from 'path';
import { fileURLToPath } from 'url';

const SPECS = [
  ['pnpm-lock.yaml', 'node_modules', 'pnpm install'],
  ['package-lock.json', 'node_modules', 'npm ci'],
  ['yarn.lock', 'node_modules', 'yarn install --frozen-lockfile'],
  ['requirements.txt', '.venv', 'pip install -r requirements.txt'],
];

export function run({
  exists = existsSync,
  stat = statSync,
  projectDir = process.env.CLAUDE_PROJECT_DIR ?? process.cwd(),
} = {}) {
  const warnings = [];

  for (const [lockfile, modulesDir, installCmd] of SPECS) {
    const lock = join(projectDir, lockfile);
    const mods = join(projectDir, modulesDir);
    if (!exists(lock)) continue;
    if (!exists(mods)) {
      warnings.push(`[setup-check-deps] ⚠ ${modulesDir} absent — lancez : ${installCmd}\n`);
      continue;
    }
    if (stat(lock).mtimeMs > stat(mods).mtimeMs) {
      warnings.push(`[setup-check-deps] ⚠ ${lockfile} plus récent que ${modulesDir} — lancez : ${installCmd}\n`);
    }
  }

  return { warnings, message: warnings.join('') };
}

/* v8 ignore next 4 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
  const result = run();
  if (result.message) process.stderr.write(result.message);
}