Claude Code Hooks

A Rust binary (kg) that Claude Code invokes before and after every tool call. It captures session data in milliseconds, invisibly.

What it is

Claude Code supports hooks - shell commands that fire at specific lifecycle events. KeepGoing registers the kg binary as a hook handler for PreToolUse, PostToolUse, and Stop events.

The binary is written in Rust and ships as a pre-built binary in the Claude plugin package. It's designed to be invisible - it reads from stdin, updates a JSON file with file locking, and exits. It never blocks Claude Code and never prints output.

Hook types

PreToolUse / SessionStart kg heartbeat

Fires before Claude uses a tool and at session start. Sends a heartbeat to keep the session marked as active. Used by the tray to show real-time "Claude is working" state.

PostToolUse kg task-update

Fires after Edit, Write, or MultiEdit tool calls. Records which file was just edited and accumulates the touched-files list for the session.

Stop / SessionEnd keepgoing save --hook

Fires when Claude finishes a response or the session ends. Runs the KeepGoing CLI to auto-save a checkpoint: captures commit hashes, touched files, and a smart summary generated from the session activity. This is the safety net — even without a manual /save, your work is captured.

statusLine kg statusline

Not a hook — a Claude Code status line renderer. Runs after each Claude response and renders the momentum dashboard at the bottom of the terminal. Amber warnings only appear when work is genuinely at risk: uncommitted edits with no checkpoint after 30+ minutes.

What it captures

Session identity

A stable session ID derived from the Claude Code process. Ties all tool calls in one conversation to a single session record.

Work phase

Whether Claude is in planning or active mode. Transitions one-way from planning to active when the first file edit happens.

Touched files

Deduplicated list of files edited during the session (capped at 200). Appended on each PostToolUse event and shown as the ✎ count in the statusline.

Heartbeat timing

Timestamps for each tool call. Used to calculate session duration and detect when a session has gone idle.

Session start SHA

The git HEAD SHA at first heartbeat. Used at render time to count commits made during the session (shown as the ↑ count).

Active task

The current task description (from the Claude Code context), stored in current-tasks.json for the tray and statusline.

Performance requirement

Claude Code hooks are synchronous - a slow hook delays Claude's response. The kg binary is therefore written to be fast above all else: no network calls, no SQLite, just a file read-modify-write on current-tasks.json using file locking.

Any error in the hook (file not found, malformed JSON, permission issue) is silently swallowed. The hook always exits 0. This ensures a failing hook never interrupts your AI workflow.

Why Rust?

Node.js startup time (~100ms) is noticeable on every Claude tool call. A compiled Rust binary starts in under 5ms. Over a long coding session with hundreds of tool calls, that's the difference between invisible and annoying.