Back to catalogue
DocumentationStopStopWhen the agent finishes its task· non-blocking
Session summary generation
At session end, captures the diff of modified files and appends it to a timestamped change log, creating an automatic changelog of what the agent produced.
Use cases
- Automatic changelog
- Change traceability
- Post-hoc review
Providers & tags
Claude Code
#documentation#changelog#git#summary
settings.json fragment
{
"hooks": {
"Stop": [
{
"hooks": [
{
"command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/session-changelog.mjs",
"type": "command"
}
]
}
]
}
}Script · .claude/hooks/session-changelog.mjs
#!/usr/bin/env node
// Génère une entrée de changelog depuis le diff git de la session (Stop)
import { execSync } from 'child_process';
import { appendFileSync, existsSync } from 'fs';
import { join } from 'path';
import { fileURLToPath } from 'url';
export function run({
exec,
append = appendFileSync,
exists = existsSync,
projectDir = process.env.CLAUDE_PROJECT_DIR ?? process.cwd(),
now = () => new Date().toISOString(),
} = {}) {
const doExec =
exec ?? ((cmd) => { try { return execSync(cmd, { encoding: 'utf8', timeout: 10_000, cwd: projectDir }).trim(); } catch { return ''; } });
const branch = doExec('git branch --show-current');
const diff = doExec('git diff --stat HEAD~1 HEAD 2>/dev/null || git diff --stat HEAD');
const commits = doExec('git log -5 --pretty="- %s (%h)"');
if (!diff && !commits) return null;
const date = now().split('T')[0];
const entry = [
`\n## ${date} — Session sur \`${branch || 'main'}\``,
'',
commits ? `### Commits\n${commits}` : '',
diff ? `### Fichiers modifiés\n\`\`\`\n${diff}\n\`\`\`` : '',
]
.filter(Boolean)
.join('\n');
const changelogPath = join(projectDir, 'CHANGELOG.md');
if (!exists(changelogPath)) {
return { written: false, message: '[session-changelog] CHANGELOG.md absent — entrée ignorée.\n' };
}
append(changelogPath, entry + '\n');
return { written: true, entry, message: '[session-changelog] ✓ Entrée ajoutée dans CHANGELOG.md\n' };
}
/* v8 ignore next 4 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const result = run();
if (result?.message) process.stderr.write(result.message);
}