Skip to content

fix(ctx_shell): detach long foreground runs to a pollable job before the host abort (#1106) - #1119

Closed
andig wants to merge 1 commit into
yvgude:mainfrom
andig:fix/1106-foreground-soft-cap
Closed

fix(ctx_shell): detach long foreground runs to a pollable job before the host abort (#1106)#1119
andig wants to merge 1 commit into
yvgude:mainfrom
andig:fix/1106-foreground-soft-cap

Conversation

@andig

@andig andig commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Fixes #1106 (and the follow-up in the comment: auto-backgrounded ids that background_action=status reports as not found).

Root cause

The 120s handoff is the MCP host aborting the tool call, not lean-ctx. When it fires it mints a task id in its own namespace; lean-ctx's registry is keyed by shell_* blake3 ids and never sees that id, so background_action=status genuinely can't resolve it. The two namespaces belong to two processes and can't be unified from the daemon side.

should_auto_background only pre-empts at timeout_ms >= 300_000 + cargo test, so any other long command (or a lower timeout_ms) runs foreground and gets stranded by the host abort.

Fix

Add a foreground soft cap below the host abort (default 110s, override LEAN_CTX_SHELL_FG_CAP_MS). Every non-explicitly-backgrounded command now runs as a managed job and is waited on inline up to the cap:

  • finishes within the cap → output returned inline, job removed from the registry (unchanged behaviour for the common case);
  • outlasts the cap → left running, and its real shell_* id is returned so the caller can always background_action=status/cancel it.

This sidesteps the host abort instead of trying to reconcile the id namespaces.

Notes / caveats

  • Relies on the cap being below the host's actual abort; configurable via LEAN_CTX_SHELL_FG_CAP_MS for hosts with a lower cap.
  • Cross-process polling of a job started in another session is still out of scope (registry lives in the daemon).

Test

New background_shell tests: fast run returns Finished inline; slow run returns Detached { job_id } with a shell_* id that status resolves. cargo test --lib background_shell — 4 passed, compiled against main.

🤖 Generated with Claude Code

…the host abort (yvgude#1106)

The MCP host aborts a ctx_shell tool call that stays in the foreground
past ~120s and hands back a task id from its own namespace, which
background_action=status cannot resolve ("not found"). The child keeps
running but its output is only recoverable via a truncated notification.

Add a foreground soft cap (default 110s, override LEAN_CTX_SHELL_FG_CAP_MS)
below the host abort: every foreground command now runs as a managed job
and is waited on inline up to the cap. Fast commands return their output
inline exactly as before; a command that outlasts the cap is left running
and its real shell_* job id is returned, so the caller can always poll or
cancel it. This sidesteps the host abort rather than trying to unify the
two id namespaces (impossible from the daemon side).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yvgude

yvgude commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Cherry-picked to main as ef16916. Thank you for the contribution!

@yvgude yvgude closed this Jul 21, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ctx_shell 120s foreground cap forces long Rust builds (clippy/fmt) into background handoff

2 participants