claude-settings: enable native auto-compact as a mid-turn safety net

This commit is contained in:
damocles 2026-09-07 13:51:33 +02:00
commit 73c5c06e31
2 changed files with 36 additions and 12 deletions

View file

@ -86,12 +86,13 @@ context (it won't carry our title). claude stores sessions in
`--name` writes the title into the file as a `custom-title` event, which
is what `--resume <title>` resolves against. We never pass bare
`--continue` (it resumes the _latest_ session in the cwd — the hijack
vector). Auto-compact, auto-memory, and dynamic workflows (the `/workflows`
feature) are disabled via the managed settings at
`/etc/claude-code/managed-settings.json`: hyperhive owns compaction
(see [Compaction](#compaction) below), and `disableWorkflows` keeps the
`/workflows` machinery from spawning sub-runs that burn usage on the
harness's autonomous turns.
vector). Auto-memory and dynamic workflows (the `/workflows` feature) are
disabled via the managed settings at `/etc/claude-code/managed-settings.json`:
`disableWorkflows` keeps the `/workflows` machinery from spawning sub-runs
that burn usage on the harness's autonomous turns. Claude's own native
auto-compact is **on**, at the widest window claude-code allows — see
[Compaction](#compaction) below for why (it's a safety net, not the
primary mechanism; hyperhive still owns that).
**Session reset** is available via `POST /api/new-session` (or
`/new-session` slash command). It does _not_ touch the session inline —
@ -105,10 +106,9 @@ turn's `--resume <title>` then misses and self-heals into a fresh session.
## Compaction
claude's own in-session auto-compact is off (via the managed settings
at `/etc/claude-code/managed-settings.json`); hyperhive owns it. The
`hive_claude::InfiniteSession` keeps the session alive across the context
window with two triggers baked into its `run`:
hyperhive owns compaction as policy: the `hive_claude::InfiniteSession`
keeps the session alive across the context window with two triggers baked
into its `run`:
- **Reactive** — claude-code prints `Prompt is too long`. The session is
_already_ past the window, so no turn can run on it — the session
@ -126,7 +126,30 @@ window with two triggers baked into its `run`:
_then_ `/compact`s, so the agent can persist in-flight state before the
detail collapses into a summary.
The **when** is a `hive_claude::CompactionPolicy` injected by the harness:
**Both triggers above are checked between hive-agent's own turns** — the
percent watermark is read from the last completed turn's telemetry
(`PercentPolicy::should_compact`, checked after `attempt()` returns), and
the reactive path only fires once claude-code has already refused a whole
turn as too long. Neither can see context growth happening _inside_ a
single long turn's own tool-calling before it returns — a turn whose tool
calls alone blow past the window hits the reactive path with no preceding
checkpoint, losing whatever wasn't already persisted (#2707, root-caused in
#3727).
**Safety net for that gap: claude-code's own native auto-compact is on**,
via the managed settings (`"autoCompactEnabled": true`,
`"autoCompactWindow": 1000000` — the CLI's documented max, so it fires only
right before the real hard limit, not as an earlier watermark). This is
deliberately _not_ the primary mechanism — it runs with no checkpoint and
none of the `CHECKPOINT_PROMPT` notes-flush machinery above, so a session
saved by it still loses whatever wasn't already durable — but it can act
_mid-turn_, underneath `InfiniteSession::run`, which the two triggers above
structurally cannot. Do not confuse this with the `hyperhive.autoCompact`
nix option below: that one is a per-agent on/off for hyperhive's _own_
proactive watermark and has no effect on claude's native mechanism, which
is fleet-wide and set once in `hive-agent/prompts/claude-settings.json`.
The **when** for hyperhive's own policy is a `hive_claude::CompactionPolicy` injected by the harness:
`turn::make_session` builds a `PercentPolicy` that compacts once the
model-reported context fill reaches `HIVE_COMPACT_WATERMARK_PERCENT`
(default **75%**), falling back to `harness_state::context_window_tokens(model)`