Background shell tasks (Claude Code run_in_background) are now first-class, kind-tagged pending work — consumers can distinguish "turn ended, truly done" from "turn ended, background work pending" and relay the auto-resumed follow-up turn instead of dropping it. Closes #61. Full design: docs/designs/2026-07-13-issue-61-background-shell-tasks.md.
⚠️ Breaking changes
Message.Subagents *SubagentStats→Message.Background *BackgroundStats— kind-tagged[]TaskCountswith comma-okKind(k); a kind's absence means untracked,{0,0}means tracked-and-quiescent. Deliberately no unionPending(): a union gate hangs on never-terminating shell work (dev servers).MessageSubagentResult→MessageTaskResult— kind-neutral; a background bash completion is not a "subagent result".MessageBackgroundTasksnow carries all task kinds via newMessage.Tasks []BackgroundTask{ID, Kind, Description}; theToolsoverload is gone. A bash-only snapshot is no longer indistinguishable from "no background work".
New
BackgroundKindopen vocabulary:BackgroundSubagent(expected to terminate),BackgroundShell(may never terminate — gate with a timeout); unknown backend kinds pass through sanitized.cli.WithShellTracking()opt-in, gated by theShellFeedBackendcapability marker — only backends with a native background-task feed (Claude) ever stamp shell counts; feed-less backends structurally cannot report a false "tracked and quiescent".- Tracker: per-kind books with per-kind caps (128 pending / 32 stamped ids), first-observation-wins kind immutability, remove-before-add snapshot application, counters move only on genuine set mutations.
Consumer contract (ADR-7)
- Subagents: wait until
Background.Kind(BackgroundSubagent)drains to zero (unchanged policy). - Shell: never gate quiescence on it — watch with a timeout; if the task exits in the window, drain the auto-resumed follow-up turn. A test suite finishing → verdict captured; a dev server → timeout lapses, finish cleanly. Bounded-vs-unbounded within "shell" is unknowable to the library; the consumer's timeout is the arbiter.
- Drain to quiescence before the next
Send— buffered follow-up results otherwise misattribute to the next prompt. - Shell stamps are actionable only on persistent (streaming) subprocesses; teardown with pending work abandons it.
Verification
Per-kind e2e assertions on live-captured fixtures (checked into testdata/backgroundtask/), property-tested tracker invariants, adversarial review (two independent passes), make qa green.
Migration: msg.Subagents.Pending() → counts, ok := msg.Background.Kind(agentrun.BackgroundSubagent); ok && counts.Pending() > 0.
Full changes: v0.8.1...v0.9.0
What's Changed
- feat: kind-aware background work — shell task quiescence + follow-up turns (#61, v0.9.0) by @dmora in #63
Full Changelog: v0.8.1...v0.9.0