Back to catalogue
NotificationPostToolUse
Tool usage tracking
See exactly how hard each session works
Increments a counter per tool type after each use and logs the activity, providing a view of the agent's usage intensity per session.
What does the Tool usage tracking hook do?
Tool usage tracking is a Claude Code PostToolUse hook. It fires automatically at that lifecycle event — outside the model, so it can't be skipped or forgotten. See exactly how hard each session works.
As a PostToolUse hook it runs after the action, reacting to what just happened rather than blocking it. Because it is a deterministic Node.js script, it executes on every matching event without relying on the model to remember — the guarantee that makes agentic workflows safe to automate.
Use cases
- Observability
- Usage analysis
- Agentic FinOps
Tags
#notification#observability#metrics#finops
settings.json fragment
{
"hooks": {
"PostToolUse": [
{
"hooks": [
{
"command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/tool-usage.mjs",
"type": "command"
}
]
}
]
}
}Script · .claude/hooks/tool-usage.mjs
#!/usr/bin/env node
// @hookstack post-bash-cost-tracker
// Journalise les commandes Bash avec leur durée (PostToolUse Bash)
import { appendFileSync, mkdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
export function run(
input,
{
append = appendFileSync,
mkdir = mkdirSync,
projectDir = process.env.CLAUDE_PROJECT_DIR ?? process.cwd(),
now = () => new Date().toISOString(),
} = {},
) {
const command = input.tool_input?.command ?? "";
if (!command) return null;
const logDir = join(projectDir, ".claude", "data");
mkdir(logDir, { recursive: true });
const entry = {
ts: now(),
cmd: command.slice(0, 500),
exit: input.tool_response?.exit_code ?? null,
};
append(join(logDir, "bash-history.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);
}