Skip to content

AI CODING ASSISTANTS

Claude Code Background Tasks: Two Surfaces, Measured

Claude Code background tasks come in two shapes: a detached session that outlives your shell, and a shell command that dies with it. We measured both.

Claude Code has two background mechanisms and they are not variations of one thing. claude --bg detaches the whole agent, which outlives the terminal that started it. The Bash tool's run_in_background detaches one shell command, and that command dies when the session ends: a 15-second job inside a 6.6-second session came back [killed], twice, against a control that passed. This guide separates the two, gives the lifecycle commands for each, and ends with the decision rule. Measured 2026-09-12 on Claude Code 2.1.269, Windows 11, Node 26.7.0.

Key takeaways

  • claude --bg backgrounds a session; run_in_background backgrounds a command. Only the first survives your shell.
  • A background session returned in 1,912 ms cold and 993 ms once the background service was already running.
  • A 15-second command inside a 6.6-second session recorded [killed]; a 1-second control in a 5.9-second session recorded exited with code 0.
  • A finished background session reports idle and done and stays resident until you stop it.
  • claude stop removes a session from the listing but keeps the conversation; we resumed one and it remembered the file it had written.

What Claude Code background tasks are

The phrase covers two unrelated surfaces that happen to share a word. One is a process-level feature of the CLI; the other is a parameter on a tool. The complete guide treats them as separate mechanisms, and running them side by side is the fastest way to see why.

SurfaceUnitLifetimeManaged with
claude --bgA whole sessionOutlives the launching shellagents, attach, logs, stop, rm
run_in_backgroundOne shell commandDies with the sessionBashOutput, KillShell

Read the table as a question about what you are detaching from. A session detaches from your terminal. A command detaches from the agent's turn, not from the agent.

Backgrounding a whole session

Pass --bg with a prompt and the CLI hands back a short id and four commands:

Terminal
claude --bg --model sonnet "Read note.txt and write its contents, uppercased, to shout.txt. Then stop."
# → backgrounded · b6382d33
# →   claude agents             list sessions
# →   claude attach b6382d33    open in this terminal
# →   claude logs b6382d33      show recent output
# →   claude stop b6382d33      stop this session

The first invocation printed Starting background service… on stderr and returned in 1,912 ms. The second, with the service warm, returned in 993 ms. Both times the prompt had barely started work; the return is a handoff, not a result.

The session then runs with no terminal attached. Ours wrote shout.txt correctly while the launching shell had already moved on. This is the surface that matters for a long running Claude job — a migration, a corpus-wide edit, an overnight refactor — because nothing about it is tied to the window you started it from.

Backgrounding one command

Inside a session, the Bash tool accepts run_in_background. The agent gets back a task id and a file path instead of output:

Tool result
Command running in background with ID: bpng2lnp0
Output is being written to: …\<session-id>\tasks\bpng2lnp0.output

That is the whole mechanism. The command is spawned, its output is appended to a file under the session directory, and the agent reads the file later instead of blocking on the process. The session we measured returned its answer in 6,078 ms while the command it started was still running.

This is the right tool for a dev server, a watch process, or a test suite whose output the same conversation will act on — work that belongs to the session and has no reason to outlive it.

The command that did not survive

We asked a print-mode session to start a 15-second command with run_in_background and not wait for it. The session finished first. The output file read:

tasks/bpng2lnp0.output
[killed]

No LONG_DONE, no exit code. To rule out a broken probe we ran three arms:

Command lengthSession durationOutput fileCompleted
15,000 ms6,580 ms[killed]No
15,000 ms6,078 ms[killed]No
1,000 ms5,860 msLONG_DONE then exit code 0Yes

The control completed. The bound is the session's lifetime, not the command's length, and Claude Code kills the child rather than orphaning it. That is defensible behaviour — an abandoned build process is worse than a cancelled one — but it is not what the word background implies, and nothing in the tool result warns you.

Which one to reach for

The decision rule is one question: does the work need to survive this conversation?

  • Yes. Use claude --bg for overnight jobs, anything you want to close the laptop on, anything you will come back and read.
  • No. Use run_in_background for dev servers, watchers, log tails, and a long test run the same session will interpret.
  • Neither. Use a foreground tool call. Most work is faster inline, and the measured cost of unnecessary delegation is in the subagents guide.

A background session is a full agent with its own context window, so it is not a cheap way to parallelise a small task. It is a way to stop paying attention.

Reading a background session

The listing command is interactive-only:

Terminal
claude agents
# → 'claude agents' requires an interactive terminal (stdout is not a TTY) —
# →  use 'claude agents --json' for a machine-readable listing.

claude agents --json is the scriptable form, and it returns more than you asked for. Our listing included the interactive session we were typing in, marked kind: "interactive", alongside the background one. Only background entries carry the short id and a state field, so filter before counting:

Terminal
claude agents --json | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{for(const x of JSON.parse(s))if(x.kind==='background')console.log(x.id,x.status,x.state)})"
# → b6382d33 idle done

Two details are worth internalising. A finished session reports idle and done and is still resident — the process does not exit when the task completes, because a session waits for input by definition. And claude logs replays the terminal buffer, escape sequences and spinner frame included, rather than printing a transcript; for the conversation itself, read the session file described in where Claude Code stores history.

Stopping is reversible. claude stop b6382d33 removed the session from the listing, and a later claude --resume against its full session id answered a question about the file it had written before it was stopped. claude rm is the one that deletes. Anthropic's CLI reference documents the flags; the lifecycle states here are ours.

What did not work

claude agents refused to run at all. Every scripted example in the first draft piped it somewhere, and it exits with a TTY complaint instead. The complaint names its own fix, which is better than most, but it means the obvious listing command is the wrong one for automation.

claude logs was going to be the evidence block. It replays the terminal, so redirecting it to a file produced colour codes, cursor moves and a half-drawn processing spinner. It is a debugging aid for a person, not a log in the tail -f sense.

The kill was almost published as a broken probe. The first 15-second run returned [killed] with no output, which looks exactly like a malformed command. The one-second control is what turned it into a result, and both are committed in the fixture rather than described.

Best practices

  • Pick the surface by lifetime, not by duration. A four-hour job that belongs to this conversation is still run_in_background; a two-minute job you want to walk away from is still --bg.
  • Filter claude agents --json on kind. Your own interactive session is in that array.
  • Stop sessions you have finished with. idle means resident, and a forgotten agent is a process holding a working directory.
  • Use claude rm deliberately. stop is reversible and rm is not.
  • Redirect important output to a real file rather than relying on the task file, which is scoped to the session that created it.
  • Give background sessions narrow prompts. You are not there to correct them, and correcting one costs a reattach.

Common mistakes

Expecting run_in_background to detach a build. It detaches the turn. The process dies with the session, we measured it twice, and the failure is silent: [killed] in a file nobody reads.

Reading idle as finished and gone. The task is done; the agent is not. It waits for input that will never arrive until you attach or stop it.

Scripting against claude logs. You will be parsing escape sequences. Read the session transcript instead.

Treating --bg as parallelism. Each background session is a full agent with its own window and its own bill. Three of them cost three sessions, not one split three ways.

Forgetting that the first start is slower. The gap between 1,912 ms and 993 ms is the background service warming up. It is not a hang, and re-running the command creates a second session.

Conclusion

Use claude --bg when the work should outlive the terminal and run_in_background when it should not; that single question settles every case. The measurement worth carrying away is the one nothing in the interface tells you — a command started with run_in_background is killed when its session ends, confirmed twice against a control that passed. If you have been using it for anything you intended to walk away from, those jobs have been dying quietly. Move them to a background session and check the output file once.

Frequently asked questions

What are Claude Code background tasks?
Claude Code has two separate background mechanisms. The --bg flag detaches an entire session, which keeps running after the launching terminal closes and is managed with claude agents, attach, logs, stop and rm. The run_in_background option on the Bash tool detaches a single shell command inside a session, writing its output to a file the agent reads back.
Does run_in_background keep running after Claude exits?
No. We started a 15-second command with run_in_background inside a print-mode session that finished in 6.6 seconds. The output file read killed and the command never printed. A one-second control in a 5.9-second session completed and recorded exit code 0, so the bound is the session lifetime, not the command.
How do I run a long running Claude task in the background?
Use claude --bg with your prompt. It prints a short id and returns immediately — 1.9 seconds on the first run and 993 milliseconds afterwards on our Windows machine. The session survives the shell that started it. Reattach with claude attach, stop it with claude stop, and delete it with claude rm.
Why does claude agents fail in a script?
The command refuses to run when stdout is not a terminal, printing a message that names the fix: use claude agents --json for a machine-readable listing. The JSON form also returns your current interactive session alongside background ones, so filter on kind equal to background before counting anything.
Does stopping a background session delete the conversation?
No. After claude stop the session leaves the agents listing, but the conversation is kept on disk. We resumed a stopped background session by its full session id and it answered a question about work it had done before being stopped. Only claude rm deletes it.

Muhammad Kashif

Founder and editor of Devventa, covering AI coding assistants, Next.js and the modern AI development stack.