Let a command see the session it is running for, and retire the alias that stood in for it - #51
Merged
Merged
Conversation
CLAW_SESSION_ID was set on the sandbox and then filtered out before any model-issued command could read it, so a run could not name the session it belonged to. Two mechanisms removed it, and neither was aimed at it. The child environment is an allowlist -- WORKSPACE_FACING, built up rather than filtered down so that no future secret arrives by default -- and the session id was simply never added to it. The other route in, the per-request env file, refuses every BOOTSTRAP_OWNED name so that a request cannot overrule what this process was launched with; CLAW_SESSION_ID is on that list for the good reason that a request must not rewrite its own session id, and the side effect was that the file could not carry it either. What made this invisible is that the same value already reached the child under a second name. HYPERLOOM_SESSION_ID is set on the adjacent line and is not bootstrap-owned, so it passes -- and the name every consumer actually reads did not. Hyperloom's manifest and its LLM attribution both read CLAW_SESSION_ID; on a real run against this cluster, manifest.json recorded `claw_session_id: null`, so Claw-session correlation has never worked. Adding the name to WORKSPACE_FACING costs no secrecy: the identical value is already exposed under the other name, it is an identifier rather than a credential, and the credential this list exists to withhold -- AUTH_CLAW_TOKEN -- stays omitted. Nor does it become user-writable: isClawInternalEnv already denies the whole CLAW_* prefix in user env. The alias stays for now, and a scan of the sibling repositories is what stopped it being deleted: the Hyperloom TUI resolves its session from HYPERLOOM_SESSION_ID and from no other name. A comment records that, and records what it looks like -- every other field in that file falls back to a CLAW_* name and this one does not, which is the shape of a consumer that found CLAW_SESSION_ID empty. The alias is a workaround for this bug, not a second contract, and it can go once that consumer reads the platform's own name. Test added for the visibility, alongside the existing one that scans the whole child environment for the token's value. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
zoroyihan7
force-pushed
the
fix/claw-session-id-reaches-child
branch
from
September 17, 2026 04:48
03bac77 to
304f447
Compare
It existed because the platform's own name for the session could not be read from inside a sandbox. The parent commit fixes that, so the alias is carrying nothing the line above it does not. Both halves go: the injection in ensure-hands.ts, and the user-env deny entry that reserved the name. Nothing in this repository reads it, and the one consumer outside it -- the Hyperloom TUI, which resolved its session from this name and no other -- reads CLAW_SESSION_ID as of AMD-AGI/Hyperloom-Web's fix/tui-session-id-from-claw. Merge order matters, which is why this is a commit of its own rather than part of the fix. Landing it before that TUI change ships leaves an older TUI unable to find the session it is running inside; it degrades rather than crashes -- initializeSession falls through to createSession() and the run gets a fresh session instead of the one it is sitting in -- but it is a regression, and it is avoidable by waiting. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
weilei0120
approved these changes
Sep 17, 2026
zoroyihan7
added a commit
to AMD-AGI/Hyperloom
that referenced
this pull request
Sep 17, 2026
… the run The rule said: under Claw (`$CLAW_SESSION_ID` set) use the bash tool's `run_in_background=true`, everywhere else `setsid nohup ... &`. The intent was right and the test was unreachable -- `$CLAW_SESSION_ID` never reached the shell a model's command runs in, so every agent following this fell through to `setsid nohup`, which is the form the rest of this document exists to prevent, failing the way it warns: invisibly, from inside the run. That is fixed in AMD-AGI/PrimusClaw#51, so the test now answers. It is not sufficient on its own, though. Being on the platform does not say the deployment serves background shells: with them switched off the bash tool has no `run_in_background` parameter at all, and `setsid nohup` is then correct even there. So the rule takes both -- the session id for "something is reclaiming this sandbox on what it can see", the parameter for "and there is a tool call to hand the block to". Keying on the parameter alone was considered and is wrong in the other direction: agent harnesses off-platform have background modes of their own, and pointing a local run at one regresses exactly what `setsid` is there for, since nothing off-platform reclaims a sandbox and such a shell may not outlive the connection that started it. Every site that stated the rule moves together: the packaged SKILL.md (the definition, the launch block and the robustness monitor), operations.md (the detach rule, the pid reconciliation and the monitor), the three example skills, and the two pre-release demo prompts. The prompts keep the literal `setsid nohup`, which test_pre_release_stall_liveness asserts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
CLAW_SESSION_IDis set on the sandbox and then filtered out before any model-issued command can read it. Inside a sandbox,echo $CLAW_SESSION_IDis empty.Two mechanisms remove it, and neither is aimed at it:
WORKSPACE_FACINGinhands/src/runtime/child-privilege.ts, built up rather than filtered down so no future secret arrives by default. The session id was simply never added.BOOTSTRAP_OWNEDname so a request cannot overrule what the process was launched with.CLAW_SESSION_IDis on that list.Why nobody noticed
The same value already reached the child under a second name.
HYPERLOOM_SESSION_IDis set on the adjacent line ofensure-hands.tsand is not bootstrap-owned, so it passes. The name every consumer actually reads did not.In AMD-AGI/Hyperloom the run manifest (
inference_optimizer/session/manifest.py), the LLM attribution (common/llm_attribution.py), the optimizer bootstrap (inference_optimizer/cli/bootstrap.py) and the specialist subprocess env allowlist (orchestrator/specialists/subprocess_.py) all readCLAW_SESSION_ID. On a real run, the manifest recorded:So the session correlation those paths exist to provide had never worked — the session breakdown always stored null and trace grouping always fell back. Other downstream tooling reads the same name and silently degrades to a generic session id.
It also broke a documented contract in the other direction: Hyperloom's optimizer skill told an agent to branch on whether
$CLAW_SESSION_IDis set to choose how it detaches a long run. That branch could never take its sandbox side. (Fixed separately in AMD-AGI/Hyperloom#1400, by keying on the bash tool instead.)The change
Two commits.
fix(hands)— one name added toWORKSPACE_FACING, plus a regression test.WORKSPACE_FACINGis the right lever rather than an exemption inBOOTSTRAP_OWNED, and not because the latter would not work — user-supplied env is already denied the wholeCLAW_*family byisClawInternalEnv, andensure-handsassigns this key after spreading the caller's env, so it could not be spoofed either way. It is that the launch command is the authoritative source: it carries the value directly, so the child gets it even on a path that writes no per-request env file at all, whereAPPLIED_ENV_KEYSis empty and the other route yields nothing.It costs no secrecy: the identical value is already exposed under the other name, it is an identifier rather than a credential, and the credential the list exists to withhold —
AUTH_CLAW_TOKEN— stays omitted.chore(brain)— retireHYPERLOOM_SESSION_ID: the injection inensure-hands.tsand theuser-env.tsdeny entry that reserved the name.The alias was never a second contract. Its one reader outside this repository resolved its session from that name and from no other, while falling back to a
CLAW_*name for every other field it parses — the shape of a consumer that triedCLAW_SESSION_ID, found it empty, and used the name that worked. That reader now consultsCLAW_SESSION_IDas well, so nothing is left depending on the alias.INFERENCE_OPTIMIZER_SESSION_LAYOUTon the following line has no reader I could find either, but it carries configuration rather than a duplicate identifier and is also injected by an unrelated path, so it is left alone here.Verification
Unit: the
claw/packages/handssuite, 223 tests, 222 pass. The one failure (a zombie is not work…) needspython3, which the runtime image does not carry; it fails the same way on unmodifiedmain. The new regression test sits alongside the existing test that scans the whole child environment for the token's value — that one still passes, which is the point: the session id is visible and the credential is not.End to end, on a cluster running this branch, driving a real GPU workload through a sandbox:
CLAW_SESSION_IDreads back inside the sandbox as the session's own id;HYPERLOOM_SESSION_IDis gone.run_in_background=true, and the job outlived the agent turn.claw_session_idinstead ofNone— the correlation working for the first time.idle_handle_kept_background_work running=1), flipped to idle within one probe interval of the job exiting, and reclaimed the sandbox shortly after. Both directions of the gate behave.