Skip to content

A claude --bg agent inherits the daemon's environment, not the spawner's — so the suite does not reach it #335

Description

@Wirasm

A claude --bg agent does not inherit the environment of whoever spawned it, so HELM_DEFAULTS_SUITE and HELM_MAIL_DIR do not reach it — and an isolated helm's background agent claims its mailbox in the operator's live ~/.helm/mail.

Measured in spike #330, from an agent tool call inside a real helm pane. Claude Code 2.1.226.

What was measured

Three --bg workers were started with three different HELM_MAIL_DIR values. All three claimed in the first one. One of them also reported seeing the spawner's HELM_PANE, which it was never given.

The cause is architectural rather than a bug in the flag. claude --bg does not fork a fresh process from the caller: it hands the job to a supervisor daemon reparented to launchd, which keeps pre-warmed bg-pty-host spares already running. Ancestry, measured:

bg-spare ← bg-pty-host ← claude daemon run ← launchd(1)

The spare's environment was captured when the daemon started. Only argv is per-job. So every environment variable a --bg agent sees belongs to whichever session happened to start the daemon — which is also why spawn is sub-second and why nothing can orphan it.

Why this matters here

This is #285 arriving through a door #285's fix cannot reach. That ticket existed because a throwaway instance under HELM_DEFAULTS_SUITE claimed mailboxes in the operator's live root — addressable by his real agents, listed to them, and swept by the reaper on every session start. It was fixed by making the mailbox follow the suite, and the fix works: helm declares the decided suite into every pty child (PaneEnvironment.suiteDeclaration) and both writers resolve it.

A --bg agent is not a pty child of helm. Nothing helm declares reaches it. So the isolation promise — "no reachable path to the operator's state" — is false again for this one spawn path, and the mechanism that made it true cannot be pointed at the problem.

It also breaks the thing that makes capability testing safe: every spike run today was safe against a live machine because the suite isolates. A spike that reaches for --bg loses that without being told.

What to decide

  • Can helm influence the daemon's environment at all? If the daemon is started on first use, a helm that starts it deliberately — with the suite already set — would give every subsequent job the right root. Worth measuring: does the daemon exit when idle (the spike observed idle_exit after 1394 s), and does the next job start a fresh one that would capture a new environment?
  • Is there a per-job lever? Only argv is per-job today. --settings is argv and already carries other decisions — determine whether anything in it can set or override what the mailbox writers read, or whether the writers should learn to read a flag as well as an env var.
  • Or is the honest answer that --bg is not usable where isolation is required? That is a legitimate outcome, and if so it belongs in AGENTS.md beside the suite's own promise, which currently reads as unconditional.

Acceptance

Related: #285 (the mailbox following the suite), #330 (the spike), #315 (the fix this bypasses).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions