Skip to content

fix(claude): switch model, effort and permission mode in place - #28

Merged
dviejokfs merged 2 commits into
mainfrom
fix/claude-live-config-changes
Oct 3, 2026
Merged

dviejokfs merged 2 commits into
mainfrom
fix/claude-live-config-changes

Conversation

@dviejokfs

Copy link
Copy Markdown
Contributor

Problem

Changing a retained Claude turn's model, effort or permission mode replaced the Claude process. The reuse check compared those settings, and on any difference called terminate() on the parked process without looking at what it was running. Background subagents were stopped, background shells were orphaned, and their completions never reached a later turn.

Confirmed live with haiku before the fix: in each of cfg-model, cfg-effort, cfg-permission and cfg-model-agent, the next turn ran in a new Claude process and the background task's completion was lost.

Fix

  • Switch in place. Model, effort and permission mode are left out of the process fingerprint for Claude. After claiming the process, the runtime sends set_model, apply_flag_settings {effortLevel} and set_permission_mode, and waits for each success before writing the prompt. Background output that arrives meanwhile is parsed and buffered exactly as while parked.
  • Never stop background work implicitly. Some changes still need a new process: the working directory, launch context/MCP servers, sandbox, harness options, thinking off, ultracode, returning to the CLI's default model or effort after launching with one, and entering bypass mode without its launch flag. If background work is running when such a change arrives, the turn now fails with the new RuntimeError::RestartWouldStopBackgroundWork, which names the work (RuntimeBusy, RequiresUserAction, DeliveryState::NotSent). The process is left running. A switch Claude refuses is handled the same way, and the process goes back to its background work, with its settings marked unknown so the next turn resends them in full.
  • Health check. The health probe is skipped after a successful switch, because the answers already prove the process is live. Otherwise the status frame Claude sends after set_permission_mode made the probe replace a healthy process.
  • New adapter hook. AgentAdapter::retained_background_summary describes the running work for the error.

Tests

  • Fake-Claude integration tests (tests/retained_live_messages.rs):
    • a switch keeps background work, and the completion reaches the next turn;
    • a change needing a new process is refused while work runs, then allowed after it finishes;
    • a refused switch hands the process back to its work.
    • The first one fails without the health-probe fix.
  • Unit tests for flag parsing, the fingerprint, and which switches are possible in place.
  • Updated test. claude_permission_change_replaces_with_single_pool_slot asserted the old behaviour. It is now claude_permission_change_is_switched_in_place, and its single-pool-slot coverage moved to a thinking-off change.
  • Live smoke (examples/claude_live_messages_smoke.rs, haiku): all 12 scenarios pass, the existing 8 plus cfg-model, cfg-effort, cfg-permission and cfg-model-agent. After the model change the next turn reported claude-sonnet-5-5.
  • CI gate locally: fmt, clippy -D warnings on 1.99, cargo test --all-features (425 tests), docs, 1.88 MSRV check.

Not in this PR

Background shells survived the old replacement, running outside the process tree the SDK terminates. That leak is separate and still open.

🤖 Generated with Claude Code

Changing any of them between turns replaced the retained Claude process,
stopping background subagents and orphaning background shells, and lost
their completions. The process now switches them with set_model,
apply_flag_settings and set_permission_mode before the prompt, buffering
background output that arrives meanwhile.

A change that does need a new process (working directory, launch context,
sandbox, thinking off, ultracode, going back to a default model or effort,
entering bypass mode without its launch flag), or a switch Claude refuses,
no longer stops running background work: the turn fails with
RestartWouldStopBackgroundWork naming that work, and the process goes back
to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[High risk] Changes how the Claude process handles configuration updates between turns.

The PR appears safe to merge; no outstanding finding or actionable new defect was established.

Summary

The PR switches a retained Claude process’s model, effort, and permission mode in place, and refuses changes that require a restart while background work remains. Since the previous review, it also buffers unsolicited frames written during a switch and delivers them to the next turn. The previous thread is resolved.

Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Claim retained Claude process] --> B[Send settings requests]
  B --> C{Switch succeeds?}
  C -->|Yes| D[Buffer unsolicited frames]
  D --> E[Send prompt and deliver buffered frames]
  C -->|No, background work remains| F[Return process to background work]
  C -->|No, no background work| G[Replace process]
Loading

Reviews (2) · Last reviewed commit: "fix(claude): keep frames an idle process..."

Comment thread src/runtime.rs Outdated
…itch

A frame Claude wrote between the answers to a settings switch on an idle
process, such as its announcement of a permission change, was dropped. It
is now kept, in order, and read by the turn before its own output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dviejokfs

Copy link
Copy Markdown
Contributor Author

@greptile-apps review

@dviejokfs
dviejokfs merged commit 0c82c01 into main Oct 3, 2026
7 checks passed
@dviejokfs
dviejokfs deleted the fix/claude-live-config-changes branch October 3, 2026 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant