fix(bash): make an unknown shell session say which id would have worked - #7
Merged
Conversation
A host that caps MCP tool calls backgrounds the call when it outruns that
cap and hands back a task id of its own -- Claude Code prints "moved to the
background as task k31b54d8q ... use TaskStop with task_id". That id
addresses the host's task, never a managed shell, so feeding it back as
bash(id=...) can only fail; the real shell handle is the shorter id inside
the completion payload that arrives later. Two id-spaces, and the error
named neither:
unknown shell session: k31b54d8q
which is true, unhelpful, and leaves the caller with no next move -- the
reported symptom was hitting it three times in one session.
The registration file already tracks every session this MCP process owns
(``managed_bash`` rows written by _record_mcp_managed_bash), so the answer
was on disk the whole time. Read it and name the live handles, and call out
the host-task-id shape when the unknown id has it:
unknown shell session: k31b54d8q -- looks like a host background-task id
(TaskStop/task output take it), not a shell id; live sessions: v334oo
Hint only: the shape check never rejects, and an unrecognised id still
fails exactly as before. bg=true was never affected -- it returns the shell
id in a response that completes before any host cap can fire.
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
This was referenced Sep 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
When a
lc bashcall outruns the host's MCP tool cap, Claude Code backgrounds the call and hands back a task id of its own:That id addresses the host's task. The shell handle is a different, shorter id (
8muo9e) that only appears inside the completion payload delivered later. Feeding the task id back asbash(id=k1i17zsgt)therefore can only fail, and the error named neither id-space:True, unhelpful, no next move. Reported after hitting it three times in one session.
bg: truewas never affected — it returns the shell id in a response that completes before any host cap fires.The fix
session_state.pyalready tracks every session this MCP process owns —_record_mcp_managed_bashwritesmanaged_bashrows into the process's registration file. The answer was on disk the whole time; nothing read it back. Newlive_managed_bash_ids()does, and the error now names the handles that would have worked:The host-task-id shape check (9 lowercase alphanumerics; managed shell ids are 6) is a hint only — it never rejects, and an unrecognised id still fails exactly as before. No timing, no id generation, no control flow changed.
Why not the other fix
The alternative is lowering lc's own soft timeout below the host's so lc always answers first with its own handle (
LEMONCROW_BASH_SOFT_TIMEOUT=100, no code change needed). That works but breaks the documented long-wait contract:bash(id=X)withtimeout=21600for a build would start returning handles at 100s, forcing exactly the sleep-polling the tool description tells callers not to do. Rejected. The host cap is also raisable from the other side viaMCP_TOOL_TIMEOUT.Scope
Open-source only —
mcp/bash.pyandmcp/session_state.py. The compiledlemoncrow.pro...bash_execmints and polls sessions and is untouched.Verification
Those 13 failures are pre-existing — the identical 13 fail on the parent commit with these three files reverted (194 passed there; the +2 are the new tests). Same for the 10
mypy --stricterrors onbash.py, allno-any-returnfrom the compiled engine's untyped surface: identical count before and after.ruff checkclean on all three files.Upstream-worthy: this is
lemoncrow-labcode, not a fork artifact.