Back to catalogue
NotificationSessionEndSessionEndOn Claude Code session end· non-blocking
End-of-session audit log
At session end, writes an audit line (timestamp, end reason, directory) to a local log file for DevSecOps traceability.
Use cases
- Traceability
- DevSecOps audit
- Usage reporting
Providers & tags
Claude Code
#notification#audit#logging#devsecops
settings.json fragment
{
"hooks": {
"SessionEnd": [
{
"hooks": [
{
"command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/audit-log.mjs",
"type": "command"
}
]
}
]
}
}Script · .claude/hooks/audit-log.mjs
#!/usr/bin/env node
// Enregistre un résumé de session dans ~/.claude/audit-log.jsonl (SessionEnd)
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 = {
timestamp: now(),
project: projectDir?.split('/').pop() ?? 'unknown',
session_id: input.session_id ?? null,
total_cost_usd: input.total_cost_usd ?? null,
num_turns: input.num_turns ?? null,
};
append(join(logDir, 'audit-log.jsonl'), JSON.stringify(entry) + '\n');
return entry;
}
/* v8 ignore next 4 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const input = JSON.parse(readFileSync(0, 'utf8'));
run(input);
}