Hooks
Hooks run automatically — you don’t invoke them. They fire at specific points in the Claude Code lifecycle and produce the status line, context nudges, and alerts Prism shows you in your terminal.
The four hooks live in optra-prism-plugin/hooks/scripts/ and are wired up in hooks.json:
| Hook | Claude Code event | Script |
|---|---|---|
SessionStart | Claude Code launches | session-start.sh |
UserPromptSubmit | You hit enter | submit-handler.js |
Stop | Claude finishes a turn | stop-handler.js |
PostCompact | You run /compact | compact-handler.js |
What you’ll see
Section titled “What you’ll see”The status line (before prompts)
Section titled “The status line (before prompts)”After each turn, Prism builds a compact one-line summary and prints it above your next prompt:
[Prism] 5.2s · 12K in / 2K out · $0.23 ($1.45 total) · turn 5- Response time — color-coded: green < 5s · yellow < 15s · red ≥ 15s
- Tokens — turn input / output, rounded to thousands
- Cost — turn cost · session total. When the turn cost isn’t cache-aware, a
~prefix marks it (the fallback full-input estimate is shown instead of the exact cached number) - Turn count — turn number in this session
The status line is built by the Stop hook (Claude Code doesn’t display stop-hook stderr, so the line is saved to session state and actually printed by the next UserPromptSubmit hook). Toggle with /prism:status → “toggle status line” (sets showStatusLine in config).
Context-management nudges (before prompts)
Section titled “Context-management nudges (before prompts)”The UserPromptSubmit hook checks turn count and token growth on every turn, and prints one line when a threshold is crossed:
| When | Color | Suggestion |
|---|---|---|
| Turn count > 80 or context grew > 10× | Red | /clear to start fresh |
| Turn count > 20 and context grew > 3× | Yellow | /compact to free context |
| Every 15 turns | Dim | Gentle /compact reminder |
Growth is lastTurnInputTokens / firstTurnInputTokens.
Periodic alerts (after responses)
Section titled “Periodic alerts (after responses)”The Stop hook also queues a small number of alerts — displayed by the next submit hook alongside the status line — to avoid repeating on every turn:
| Alert | Cadence | What it says |
|---|---|---|
| Context alert (red) | Every 5 turns, when turn count > 80 or growth > 10× | Session is deep; consider /clear |
| Context alert (yellow) | Every 5 turns, when growth > 3× and turn count > 10 | Context grew; run /compact |
| Context reminder (dim) | Every 15 turns | Periodic /compact reminder |
| Model overkill | Every 10 turns, when ≥ 3 Opus turns produced < 200 output tokens | Suggests /model sonnet for simple tasks |
| Slow response | Every 5 turns, when the last 3 turns averaged > 20s | Context may be too large; try /compact |
How costs are computed
Section titled “How costs are computed”The Stop hook computes per-turn cost using the turn’s token counts. It’s cache-aware when possible: the hook queries OTEL telemetry for cache_read_tokens and cache_creation_tokens and stores the rates in session state so the next turn’s cost calc can apply them. When no cache data is available, the hook falls back to the full input rate as a conservative estimate — and marks the displayed cost with a dim ~ prefix.
Per million tokens:
| Model | Input | Output | Cache read | Cache write |
|---|---|---|---|---|
| Opus 4.6 | $15.00 | $75.00 | $1.50 | $18.75 |
| Sonnet 4.6 | $3.00 | $15.00 | $0.30 | $3.75 |
| Haiku 4.5 | $0.25 | $1.25 | $0.025 | $0.3125 |
If the model name doesn’t match any of the above, pricing falls back to the family (“opus” / “sonnet” / “haiku”); if that fails too, cost is omitted from the status line.
What each hook does
Section titled “What each hook does”SessionStart
Section titled “SessionStart”Runs when Claude Code launches.
- Reads the API key from
CLAUDE_PLUGIN_OPTION_apiKey(Claude CodeuserConfig) or the legacy~/.prism/config.json. If missing or malformed, prints a setup prompt and exits without blocking the session. - Resolves
ingest_url,gateway_url, andanthropic_base_urlfrom the config cache (~/.prism/config-cache.json), falling back to a live fetch and then to production URLs. - Detects the active OTEL config scope (
user,project,both, ornone) and re-syncs the OTEL env vars in that scope’s settings file if they’ve drifted. Warns if both scopes hold OTEL vars simultaneously. - Writes runtime env to
$CLAUDE_ENV_FILEso the current session picks upPRISM_GCK_KEY,PRISM_THRESHOLD, and — when gateway routing is on —ANTHROPIC_BASE_URLandANTHROPIC_CUSTOM_HEADERSwith the gateway API-key header. - Prints a one-time notification when the plugin version has changed since the last session.
- Resets
${CLAUDE_PLUGIN_DATA}/session-state.jsonfor the new session. - Prints a confirmation line with the resolved ingest / gateway / Anthropic endpoints.
UserPromptSubmit
Section titled “UserPromptSubmit”Runs before Claude processes each prompt.
- Lets
/prism:…commands through immediately. - If no API key is configured, prints a setup reminder and exits 0 (prompt still goes through).
- Prints the status line from the previous turn (saved by the
Stophook) and any queued alerts. - For short / navigational / slash-command / shell-passthrough prompts, it skips nudge processing — but still captures the prompt to Ingest.
- Writes
~/.prism/advisor-context.jsonwith current session metrics (turn count, token growth, response times, model mix) so/prism:advisorcan tailor its advice. - Emits a single context-management nudge if a threshold is crossed.
- Records the prompt submit timestamp (used by the next
Stophook to measure response time). - Captures the prompt (first 2000 characters) to the Ingest service.
The submit hook always exits 0 — it never blocks your prompt.
Runs after Claude finishes a turn.
- Increments
turnCount, accumulates token totals, tracks per-model turn counts, and flags Opus turns with < 200 output tokens. - Computes the turn cost (see “How costs are computed”).
- Measures elapsed time between the prompt submit and the stop event.
- Builds the status line string and stores it in
state.pendingStatusLinefor the submit hook to display next turn. Queues periodic alerts instate.pendingAlerts. - Asynchronously sends the response (first 2000 characters) + turn metadata to Ingest.
- Asynchronously queries OTEL telemetry for this session’s cache token data and stores the result in
state.lastCacheDatafor the next turn’s cost calc.
PostCompact
Section titled “PostCompact”Runs after /compact successfully completes. Resets the counters that measure since the last compaction:
turnCount,firstTurnInputTokens,lastTurnInputTokensresponseTimes,opusLowOutputCount,modelCountstotalCost,lastCacheData- Any pending status line or alerts
So nudges restart from a clean baseline immediately after the compact.
Error behavior
Section titled “Error behavior”Every hook catches its own exceptions and exits 0. Hooks are fail-open: if any step inside a hook fails, your session continues normally — you just might not see that turn’s status line, nudge, or alert. Detailed failure context is written to the plugin debug log (~/.claude/plugins/data/prism-inline/debug.log).
Prompt-quality scoring runs server-side (in the Prism Engine) after the prompt is captured; in-terminal prompt coaching is on-demand via /prism:advisor.