Skip to main content

Module precompact

Module precompact 

Source
Expand description

precompact subcommand.

Registered as Claude Code’s PreCompact hook (see docs/specs/SPEC_COMPACTION_DETECTION_AND_HANDLING_2026_07_31.md §4.2 / Tier 1). Fires synchronously the instant compaction begins — the only real-time “it’s happening now” signal available, since the compact_boundary stream-json frame (agentmux-srv’s claude.rs translator) only arrives after compaction finishes.

Contract corrections vs PreToolUse (see hook.rs, whose code pattern this mirrors but whose payload shape it does not):

  • PreCompact’s stdin payload carries only the common hook fields (session_id, transcript_path, cwd, permission_mode, hook_event_name) — there is no trigger field on stdin. Claude Code requires a matcher ("manual" | "auto") in settings.json for PreCompact and provides no confirmed wildcard, so agent_config.rs registers two separate hook entries, each invoking this binary with a different static --trigger= argv value baked into the command string. That’s the only way this binary learns which trigger fired.
  • This is observe-only: unlike PreToolUse’s passthrough() (which prints {} to mean “no opinion”), PreCompact must exit 0 with no stdout output at all — not even {}. Any stdout here would be interpreted as hook output Claude Code has to parse; silence is the correct “no opinion” signal for this hook.

Every failure mode (malformed stdin, missing MPS env, unreachable sidecar) degrades to the same outcome: exit 0, nothing printed. A hook must never block or error the user’s Claude session — this is best-effort observability only, matching the “degrade silently” philosophy already documented in mps_client.rs.

Structs§

Args
CLI args for precompact.
PreCompactInput 🔒
Subset of the PreCompact stdin payload we care about. Every other field (transcript_path, cwd, permission_mode, hook_event_name) is ignored — serde drops unknown fields by default, and there’s nothing actionable in them for this hook.

Enums§

Trigger
Which PreCompact matcher fired. Baked into argv per hook entry (see the module doc comment) rather than read from stdin.

Functions§

build_payload 🔒
The compaction_started payload (agentmux_common::client_events), which srv declares too.
parse_session_id 🔒
Parse session_id out of the PreCompact stdin payload. Malformed or empty input yields an empty string rather than erroring — there is nothing useful to do with the trigger info alone without a session id, but publishing a best-effort ping is still better than silently doing nothing.
run
Entry point. Always returns Ok(()) — every failure mode degrades silently per the module doc comment; there is no error case this hook should ever surface to Claude Code’s stdout.