HookStackGitHub
Back to catalogue
WorkflowConfigChangeConfigChangeWhen configuration changes· non-blocking

Configuration change audit log

Records every change to a Claude Code configuration file (settings.json, skills, etc.) into a timestamped audit log for traceability and compliance.

Use cases

  • Track who changed the Claude Code configuration and when
  • Compliance audit on settings.json changes
  • Detect unauthorized configuration changes

Providers & tags

Claude Code
#audit#config#compliance#logging

settings.json fragment

{
  "hooks": {
    "ConfigChange": [
      {
        "hooks": [
          {
            "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/config-audit-log.mjs",
            "type": "command"
          }
        ],
        "matcher": ""
      }
    ]
  }
}

Script · .claude/hooks/config-audit-log.mjs

#!/usr/bin/env node
// Journalise les changements de configuration Claude Code (ConfigChange)
import { readFileSync, appendFileSync, mkdirSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
import { fileURLToPath } from 'url';

export function run(
  input,
  {
    append = appendFileSync,
    mkdir = mkdirSync,
    home = homedir(),
    projectDir = process.env.CLAUDE_PROJECT_DIR,
    now = () => new Date().toISOString(),
  } = {},
) {
  const logDir = join(home, '.claude');
  mkdir(logDir, { recursive: true });

  const entry = {
    ts: now(),
    project: projectDir?.split('/').pop() ?? 'unknown',
    change: input.change ?? input,
  };

  append(join(logDir, 'config-changes.jsonl'), JSON.stringify(entry) + '\n');
  return { entry, message: '[config-audit] Changement journalise.\n' };
}

/* v8 ignore next 5 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
  const input = JSON.parse(readFileSync(0, 'utf8'));
  const result = run(input);
  process.stderr.write(result.message);
}