Feature: hook callback control-plane (local server + per-invocation UUID) so hooks can trigger session operations like compaction

Open 💬 1 comment Opened Jun 3, 2026 by GlenTiki

Problem

Hooks today are reactive and read-only with respect to the session. They receive JSON on stdin (session_id, transcript_path, cwd, hook_event_name, tool details) and can inject additionalContext, return a block/deny decision, or emit a systemMessage. They can observe and gate, but they cannot drive the session they're attached to.

In particular, there is no supported way for a hook to trigger a session-lifecycle operation — compaction, /clear, /model, resume — on the running interactive claude process. PreCompact lets a hook react to compaction; nothing lets it initiate one.

Concrete case: a Stop or PostToolUse hook detects the context window is nearing its limit (or that a project-specific threshold — delegation count, token budget — has been hit) and wants to trigger compaction now, programmatically, rather than waiting for the ~auto-compaction heuristic or prompting the human to type /compact. Today this is impossible: the hook has no handle on the live session.

Note the asymmetry: the Messages API already exposes programmatic compaction (context_management.edits with the compact-2026-01-12 beta), so anything driving a session via the SDK can compact on demand. The interactive CLI's hook surface has no equivalent. This request is to close that gap.

Proposal

Expose a local control-plane server (loopback only) that Claude Code runs for the lifetime of a session, and pass each hook invocation the coordinates to call back into it. Each hook call carries a unique invocation UUID, surfaced both in the hook's stdin JSON and as part of the callback API path:

POST http://127.0.0.1:<port>/hook/<hook-call-uuid>/compact
POST http://127.0.0.1:<port>/hook/<hook-call-uuid>/clear
GET  http://127.0.0.1:<port>/hook/<hook-call-uuid>/context-usage

The UUID lets the server correlate the callback to the exact hook invocation, session, and process — so control is precise even with concurrent sessions, parallel hooks, or multiple ports in flight. The port + UUID + a per-session token would be injected into the hook environment (e.g. CLAUDE_HOOK_CONTROL_URL, CLAUDE_HOOK_CALL_ID, CLAUDE_HOOK_CONTROL_TOKEN) alongside the existing stdin payload.

Why a callback server rather than more stdout verbs

stdout-based control is fire-once and synchronous to the hook's exit. A callback server lets a hook:

  • act mid-execution and read state back (query current context usage, then decide whether to compact);
  • trigger operations that don't map onto "return a decision" (compaction, clear, resume, model switch);
  • target the right session deterministically via the UUID when several are alive.

Surface to define

  • Which operations are exposed — compaction first; clear / resume / model-switch as follow-ups.
  • Auth/scoping: loopback-only + per-session token; whether the UUID alone is sufficient capability.
  • Lifecycle: server bound to session start/stop; UUID validity window (single invocation vs. session).
  • Whether callbacks are allowed only during the hook's own execution, or also after it exits.

Prior art / context

Today the only options are the auto-compaction heuristic or nudging the human to run /compact. The Messages API proves programmatic compaction is feasible on the model side; this asks for a supported channel to invoke it (and adjacent lifecycle ops) from the interactive CLI's hook surface. It would let teams build context-budget management, delegation checkpointing, and other session-lifecycle automation as first-class hooks.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗