autoCompactWindow: per-profile bounded auto-compaction, both backends #165

Closed
agent wants to merge 0 commits from worker/autocompact-window-82bc2f-5 into main
Member

Adds an opt-in per-profile config key autoCompactWindow (Integer, tokens) to FleetConfig.Profile and wires it into both peer launchers.

  • Claude Code: appends --autocompact <window> to argv (mirrors --model), surviving the ccs <profile> wrapper.
  • opencode: has no absolute compact-at-N knob, so the window is applied as the resolved model's own limit.context (plus a required limit.output: 16384 default) in the generated opencode.json, merged via get-or-create nodes so it never clobbers a custom-provider block written for a pinned endpoint. Only applies when model: resolves to provider/model; otherwise logs a WARN naming the profile rather than a silent no-op.
  • Validated at config load to [100000, 1000000] — the band Claude Code's own --autocompact flag accepts.
  • Default (unset/null) leaves today's behaviour exactly.

Docs added to fleetd.example.yaml explaining the cross-backend semantics difference.

Tests: new tests in ClaudeCodeLauncherTest, OpenCodeLauncherTest, and FleetConfigTest. Full mvn clean install: BUILD SUCCESS, 926 tests run, 0 failures, 0 errors.

Adds an opt-in per-profile config key `autoCompactWindow` (Integer, tokens) to `FleetConfig.Profile` and wires it into both peer launchers. - **Claude Code**: appends `--autocompact <window>` to argv (mirrors `--model`), surviving the `ccs <profile>` wrapper. - **opencode**: has no absolute compact-at-N knob, so the window is applied as the resolved model's own `limit.context` (plus a required `limit.output: 16384` default) in the generated `opencode.json`, merged via get-or-create nodes so it never clobbers a custom-provider block written for a pinned endpoint. Only applies when `model:` resolves to `provider/model`; otherwise logs a WARN naming the profile rather than a silent no-op. - Validated at config load to `[100000, 1000000]` — the band Claude Code's own `--autocompact` flag accepts. - Default (unset/null) leaves today's behaviour exactly. Docs added to `fleetd.example.yaml` explaining the cross-backend semantics difference. **Tests**: new tests in `ClaudeCodeLauncherTest`, `OpenCodeLauncherTest`, and `FleetConfigTest`. Full `mvn clean install`: BUILD SUCCESS, 926 tests run, 0 failures, 0 errors.
agent added 6 commits 2026-08-24 16:55:01 +02:00
Adds `ideMcpUrl` to FleetConfig.Profile (default off). When set, the
Claude Code launcher mounts the IDE Index MCP as a second inline
--mcp-config server named `intellij`, and appends an IDE charter that
pins every ide_* call to the member's own worktree (spec.cwd()). The
charter order is role -> ide -> reply, one --append-system-prompt-file,
reply last (CB-618). The mount gate now fires on ideMcpUrl alone, not
only mcpUrl. ConfigRef treats an ideMcpUrl change as deferred, like the
other launch flags.

Never touches .mcp.json or CLAUDE.md — the mount and the rule arrive as
launch flags, so a project's own config is untouched.

Not yet done (see fleetd #162): the bridged-owned IDE lifecycle
(open on provision, close before worktree removal), and the opencode
adapter (separate ticket). fleetd.example.yaml documents ideMcpUrl and
fixes the stale parityOverlay default.

911 tests green.
Move the IDE guidance text to PeerLauncher.ideOverlayText (shared by both
launchers). ClaudeCodeLauncher drops it from the reply-charter file and writes
CLAUDE.local.md into a provisioned worktree instead, gated on a .git FILE
(safety: never writes into the primary's real .git-DIRECTORY checkout) and
registers it in info/exclude. OpenCodeLauncher mounts the intellij server and
adds the rules file to the instructions array.
git reads info/exclude from the common dir for a linked worktree (only
info/sparse-checkout is per-worktree), so the entry written into
<common>/worktrees/<name>/info/exclude was never honoured and CLAUDE.local.md
showed as untracked -- at risk of being swept into a worker's PR. Derive the
common dir (<common>/worktrees/<name> -> <common>) and write there. Found by
dogfooding a real spawn on fleet01; the test now uses the real worktree layout
and asserts the entry lands in the common dir, not the per-worktree gitdir.
The overlay pinned project_path to the worktree root. For a repo whose Maven
module is a subdir (this repo's pom is in `bridged/`, not at the root), opening
the root imports no module and every ide_* call resolves nothing. Pin and open
the module dir instead.

Two new opt-in per-Profile keys, both read only when ideMcpUrl is set:
- ideProjectDir: repo-relative module dir the IDE opens and the overlay pins;
  blank keeps the old worktree-root behaviour.
- ideOpenCommand: host command that opens that dir in the IDE at spawn, with
  {dir} substituted and run through /bin/sh -c so env (e.g. DISPLAY) can be set
  inline. Best-effort and non-fatal — a failure never fails the spawn. Blank
  keeps the manual-open behaviour. No close half yet (deferred).

Shared helpers PeerLauncher.ideProjectPath / openInIde back both launchers.
The two Profile fields ride a back-compat constructor, so every existing call
site and YAML compiles and behaves unchanged.

Tests: overlay content pins the module dir when ideProjectDir is set;
ideProjectPath resolution; openInIde no-op on a blank command. 918 tests green.
autoCompactWindow: per-profile bounded auto-compaction, both backends
CI / contract (pull_request) Successful in 41s
CI / build (pull_request) Failing after 1m37s
2757bc7185
Add opt-in Integer autoCompactWindow to FleetConfig.Profile (last field,
null/unset = today's behaviour). Validated at config load to [100000,
1000000] — the band Claude Code's own --autocompact flag accepts.

Claude Code: appends --autocompact <window> to argv (mirrors --model),
so it survives the ccs <profile> wrapper.

opencode: has no absolute compact-at-N knob (only compaction.auto/prune/
reserved/tail_turns/preserve_recent_tokens), so the window is applied as
the resolved model's own limit.context (+ a required limit.output:16384
default) in the generated opencode.json, merged via get-or-create nodes
so it does not clobber a custom-provider block. Only applies when model:
resolves to "provider/model"; otherwise logs a WARN naming the profile
rather than silently doing nothing.

Docs added to fleetd.example.yaml explaining the cross-backend semantics
difference (compacts AT the window vs. WITHIN it).
Owner

Landed on main via the cb-634-ide-mcp integration merge (450a5ed), not this PR. This branch forked from cb-634-ide-mcp, so it also carried the CB-634 work and could not merge to main on its own. The autoCompactWindow change is now in main and live on the Mac daemon (verified: claude member gets --autocompact 250000, opencode member gets limit.context). Closing as redundant.

Landed on `main` via the `cb-634-ide-mcp` integration merge (`450a5ed`), not this PR. This branch forked from `cb-634-ide-mcp`, so it also carried the CB-634 work and could not merge to `main` on its own. The autoCompactWindow change is now in `main` and live on the Mac daemon (verified: claude member gets `--autocompact 250000`, opencode member gets `limit.context`). Closing as redundant.
ltms closed this pull request 2026-08-24 19:12:57 +02:00
Some checks are pending
CI / contract (pull_request) Successful in 41s
CI / build (pull_request) Failing after 1m37s

Pull request closed

Sign in to join this conversation.