Interactive `claude` sessions are classified as background jobs post-2.1.139, causing bg-only guards to fire on user-foreground work
Summary
After the agent-view release (v2.1.139, May 11), every Claude Code session — including ones launched interactively by typing claude in a terminal — is set up with $CLAUDE_JOB_DIR, a daemon-managed state file, and a template: "bg" flag. As a result, instructions and guards that were intended for spawned/unattended background jobs now fire on user-foreground sessions too.
The most visible symptom is the worktree-isolation guard: every Edit/Write on a tracked file refuses with a "background session hasn't isolated its changes yet" error and forces the agent to do an EnterWorktree → commit → push → ExitWorktree → pull dance, even for a one-line edit in a session the user is actively typing in.
This is not a misconfiguration on the user's machine — it's the daemon's classification behavior. I reproduce it on a stock install on 2.1.143.
Repro
- macOS, fresh terminal. No
--bg, no agent-view, no shell wrappers. cd ~/some/git/repo && claude— open a normal foreground session.- From inside that session, ask the agent to make any single-file edit on a tracked file.
- Observe the Edit tool fail with:
> This background session hasn't isolated its changes yet. Call EnterWorktree first so edits land in a worktree instead of the shared checkout, then retry this edit using the worktree path. (To disable this guard for this repo, set "worktree": {"bgIsolation": "none"} in .claude/settings.json.)
- The agent's system prompt also includes the line "This session runs as a background job. The user may be chatting with you live or may have stepped away to check results later — respond naturally either way, and don't refer to yourself as 'a background agent.'" — which itself acknowledges the awkwardness.
Evidence the daemon is the cause
Process tree
A single claude invocation spawns a daemon + spare-agent pool:
44013 claude # foreground (terminal s000)
44581 claude daemon run --origin transient --spawned-by {...,"pid":44013}
44603 --bg-pty-host .../fb780c90.pty.sock 200 50 -- --bg-spare ...
44605 --bg-spare /tmp/cc-daemon-501/.../fb780c90.claim.sock
44608 --bg-pty-host .../90e4af4c.sock 162 36 -- --session-id 90e4af4c-... --agent claude
44611 --bg-pty-host .../30bad891.pty.sock 200 50 -- --bg-spare ...
44615 --session-id 90e4af4c-2ad8-4c0e-906e-7edbc3a3ad1e --agent claude
44616 --bg-spare /tmp/cc-daemon-501/.../30bad891.claim.sock
So:
- The foreground
claude(44013) auto-spawns a daemon (44581). - The daemon keeps a warm spare agent (44615) and bg-pty hosts ready, presumably so
←(agent view) feels instant. - Everything — including the user's interactive session — gets registered as an "agent" with a job dir.
Job-dir contents for the foreground session
$ env | grep CLAUDE_JOB_DIR
CLAUDE_JOB_DIR=/Users/smabe/.claude/jobs/ec39b0b1
$ cat $CLAUDE_JOB_DIR/state.json | head -20
{
"state": "blocked",
"tempo": "active",
...
"template": "bg",
"respawnFlags": ["--effort", "high", "--permission-mode", "auto"],
"name": "push-code-changes",
"nameSource": "auto",
...
"cliVersion": "2.1.143",
"cwd": "/Users/smabe/projects/HealthData",
...
}
template: "bg" is set on the user-foreground session. The daemon also auto-named the session ("push-code-changes") from the agent's last bash output, the way agent-view names spawned background jobs.
Why this is a bug, not a feature
Several harness-level behaviors were written for the old model where $CLAUDE_JOB_DIR implied "unattended bg work that may collide with the user's working copy and other parallel jobs":
- Worktree-isolation guard — refuses Edit/Write on
tracked filesuntilEnterWorktree. Sensible for an unattended job; pure friction for a user typing into the same session. - System-prompt "Background Session" block — tells the agent the user "may have stepped away." Wrong for the user-foreground case (and the prompt now has to apologize for itself with "respond naturally either way").
- Auto-naming — naming the session from agent output (
"push-code-changes") is great for unattended jobs the user finds later in agent-view. Less useful, mildly confusing, for an interactive terminal session.
Discrimination signal exists but isn't being used. The daemon already has:
--origin transientvs other origins--spawned-by {label, cwd, pid}for spawned jobs--bg/--bg-sparefor actual bg pool entries vs the user's TTY-attached session- A TTY-attached child process visible to the daemon
Any of those could classify "the user is talking to this session live" vs "this session was spawned to run unattended."
Suggested fix
Distinguish the two cases at the daemon layer and propagate to:
- Set
template: "foreground"(or omittemplate) on user-typed sessions; reservetemplate: "bg"for sessions spawned viaclaude --bg, agent-view "new background session,"Agenttool subagents,TaskAPI spawns, etc. - The worktree-isolation guard should fire only on
template: "bg", not on the presence of$CLAUDE_JOB_DIR. - The "Background Session" block in the system prompt should only be inserted for
template: "bg". - Auto-naming from agent output should only happen for
template: "bg".
The bgIsolation: "none" setting documented in the guard message is a workaround that disables protection wholesale, which is the wrong knob — users running real parallel bg work in the same repo want the protection on; they just don't want it firing on their interactive session.
Environment
claude --version→2.1.143 (Claude Code)- macOS 25.5.0 (darwin), zsh, Ghostty terminal
- Plain
claudeinvocation in a project directory, no flags, no shell wrappers
Related
- #59702 —
EnterWorktree/ExitWorktreecwd-pinning bug (filed today by another user). Compounds with this one: the forced worktree dance is the trigger surface for #59702, so fixing this issue would reduce exposure to that one too. - #59846 — Naming feedback: "agent view" conflates with the existing "agent" concept. Separate concern, same underlying conflation: "agent" and "session" are no longer cleanly distinguished post-2.1.139, and harness behaviors keyed off "is this a session?" assumptions break in surprising places.
This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗