Skip to content

Commit 9be5173

Browse files
mabry1985Automakerclaude
authored
docs: add background-agents design + roadmap (#221)
Captures current state of the bg-agent subsystem in the fork (what's already wired, what is not), maps the upstream qwen-code PRs we have not yet ported (QwenLM#3076QwenLM#3739), and sketches three phases to close the gap: - Phase A: model-facing agent control + event monitor (QwenLM#3471, QwenLM#3684, QwenLM#3687) - Phase B: TUI surface + /tasks command (QwenLM#3488, QwenLM#3642) - Phase C: cross-session resume (QwenLM#3739) Also calls out cross-cutting decisions we should make before Phase A lands: settings layout, stop-tool naming, persistence shape, gateway validation. This is a planning doc, not a spec. Per-phase code-level designs come later. Co-authored-by: Automaker <automaker@localhost> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 81795d5 commit 9be5173

2 files changed

Lines changed: 258 additions & 0 deletions

File tree

docs/explanation/_meta.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export default {
33
architecture: 'Architecture',
44
'agent-harness': 'Agent Harness',
55
'sub-agents-design': 'Sub-Agents',
6+
'background-agents-design': 'Background Agents',
67
'skills-design': 'Skills',
78
'hooks-design': 'Hooks',
89
'approval-modes': 'Approval Modes',
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
# Background Agents — Design & Roadmap
2+
3+
A maintainer-oriented map of the **background-agent** subsystem in protoCLI:
4+
what is already wired, what is intentionally deferred, and how we plan to
5+
close the gap with upstream `qwen-code`.
6+
7+
The goal of this document is not to specify a feature — much of the
8+
infrastructure already exists. It is to give us a single pass at the
9+
**shape** of the work so we can sequence the next set of ports without
10+
re-reading the upstream diff every time.
11+
12+
---
13+
14+
## 1. What "background agent" means here
15+
16+
Two related but distinct things travel under the same name in our fork:
17+
18+
1. **Background shell tasks**`run_shell_command` invoked with
19+
`is_background: true`. The process is detached, output is streamed to a
20+
file under `<projectTempDir>/<sessionId>/tasks/<taskId>.output`, and a
21+
`task_id` is returned to the model. These are the kind of tasks the user
22+
sees with `/bg list` today.
23+
24+
2. **Background subagents** — full `AgentCore` instances running in a
25+
separate execution context, communicating with the parent through the
26+
progress event bus. A subagent may itself spawn background shells; the
27+
two systems compose.
28+
29+
Both share the same lifecycle vocabulary (`running``completed` /
30+
`failed` / `killed`) and surface through the same UI hooks. The split
31+
matters for porting because upstream's recent work mostly extends path 2
32+
(headless / SDK / resume) while leaving path 1 stable.
33+
34+
---
35+
36+
## 2. Current state in the fork
37+
38+
### Core (ported and live)
39+
40+
| File | LOC | Role |
41+
| -------------------------------------------------------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------- |
42+
| `packages/core/src/backgroundShells/registry.ts` | 126 | `BackgroundShellRegistry`: tracks long-running shells, pub/sub listeners, `drainPendingNotifications()` |
43+
| `packages/core/src/backgroundShells/{types,diskOutput,notifications,watcher,index}.ts` | ~340 | Types, disk-tail capture, completion notifications, process-lifecycle watcher |
44+
| `packages/core/src/utils/backgroundProgressEmitter.ts` | 190 | Singleton typed event bus: `agent_started`, `agent_round`, `agent_tool_call`, `agent_finished`, `agent_failed` |
45+
| `packages/core/src/agents/background-store.ts` | 75 | `~/.proto/agents/background.json` persistence with 24h prune |
46+
| `packages/core/src/tools/bg-stop.ts` | 168 | `BgStopTool`: SIGTERM → SIGKILL on shell task PIDs |
47+
| `packages/core/src/tools/task-stop.ts` | (file present) | `TaskStopTool`: agent-level stop (separate from shell stop) |
48+
| `packages/core/src/tools/shell.ts` || `is_background: true` parameter; spawns detached, captures to disk |
49+
| `packages/core/src/agents/runtime/agent-headless.ts` | (file present) | Headless `AgentCore` execution path |
50+
51+
### CLI / UI (ported and live)
52+
53+
| File | Role |
54+
| --------------------------------------------------------- | -------------------------------------------------------------------------------------- |
55+
| `packages/cli/src/ui/hooks/useBackgroundAgentProgress.ts` | Subscribes to `backgroundProgressEmitter`, exposes `activeAgents[]` and `lastFinished` |
56+
| `packages/cli/src/ui/commands/bgCommand.ts` | `/bg list` — running + recent shell tasks with status, duration, output path, PID |
57+
| `packages/cli/src/ui/AppContainer.tsx` | Surfaces `lastFinished?.hitLimit` warnings into the conversation history |
58+
| `packages/cli/src/ui/components/StatusBar.tsx` | Renders `activeAgents` count |
59+
60+
### What this gives us today
61+
62+
- The model can fire-and-forget shells and look at output files later.
63+
- The model can stop a runaway shell via `bg_stop`.
64+
- The user sees a count in the status bar and a one-time warning when an
65+
agent hits its turn/time budget.
66+
- Sessions resume cleanly because shell registry state is in-memory
67+
per-session and the persistent `background-store.json` is best-effort.
68+
69+
### What this does **not** give us yet
70+
71+
- No model-facing way to send a message into a running subagent.
72+
- No UI for "what is each background agent doing right now" beyond a count.
73+
- No throttled streaming of subagent output back to the parent.
74+
- No cross-session resume of a background agent that was alive when the
75+
session ended.
76+
- `/tasks` (the upstream-managed pool view) is absent; `/bg list` is our
77+
thinner stand-in.
78+
79+
---
80+
81+
## 3. Upstream gap (April–May 2026)
82+
83+
The upstream PRs we have not yet ported, ordered by approximate dependency:
84+
85+
| Upstream PR | Title | What it adds | Dependency |
86+
| ----------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- | ------------------------------------------------------ |
87+
| **#3076** | background subagents with headless and SDK support | Headless agent runner + SDK task events | (foundation; partially landed via `agent-headless.ts`) |
88+
| **#3379** | headless support and SDK task events for background agents | Event surface for SDK consumers | builds on #3076 |
89+
| **#3471** | model-facing agent control (`task_stop`, `send_message`, per-agent transcript) | New tools the model can call to manage running agents | builds on #3076 |
90+
| **#3488** | background-agent UI — pill, combined dialog, detail view | TUI surface: pill in status, combined dialog, per-agent detail | builds on #3471 |
91+
| **#3642** | managed background shell pool with `/tasks` command | Pool view + `/tasks` slash command | independent |
92+
| **#3684** | event monitor tool with throttled stdout streaming (Phase C) | `event_monitor` tool — stream subagent stdout back to parent at controlled rate | builds on #3471 |
93+
| **#3687** | wire background shells into the `task_stop` tool | Unifies `bg_stop` + `task_stop` so the model has one stop verb | needs both stops merged conceptually |
94+
| **#3739** | background agent resume and continuation | Cross-session resume of interrupted agents | builds on #3471, #3684 |
95+
96+
**Skip list** (already-decided exclusions):
97+
98+
- All `vscode-ide-companion` schema fragments — package deleted.
99+
- `auto-memory` integration points — un-ported subsystem; PRs that touch
100+
`MemoryDialog` or `isAutoMemPath` need that stripped out.
101+
- Anything that imports `BackgroundTaskRegistry` (an upstream symbol that
102+
was never in the diff we picked up). Where upstream uses it, we use our
103+
`BackgroundShellRegistry`.
104+
105+
---
106+
107+
## 4. Proposed phasing
108+
109+
The dependency chain suggests three phases. Each phase is a single PR
110+
unless noted; each is sized to stay under the "path of least resistance"
111+
bar we have been holding for the rest of this fork's port work.
112+
113+
### Phase A — model can talk to its running agents
114+
115+
Land the upstream agent-control surface so the model has a real grammar
116+
for managing background work.
117+
118+
- **Port #3471** (model-facing agent control): `send_message` + per-agent
119+
transcript. Reconcile with our existing `task-stop.ts`.
120+
- **Port #3687** (unify shells into task_stop): collapse `bg_stop` into
121+
`task_stop` if it doesn't break our tool registry expectations. If it
122+
does, keep both and document the split.
123+
- **Port #3684** (event monitor tool with throttled streaming): adds the
124+
primary mechanism the parent uses to actually consume subagent output.
125+
126+
Risk: our `BackgroundShellRegistry` and upstream's task-pool shape may
127+
have diverged. Expect a non-trivial reconciliation in the registry's
128+
public methods.
129+
130+
Effort estimate: **medium-large**. Two cherry-picks plus a glue PR.
131+
132+
### Phase B — user can see what's happening
133+
134+
Once the model has a control surface, expose it.
135+
136+
- **Port #3488** (UI: pill, combined dialog, detail view). This will
137+
conflict heavily with our existing StatusBar + AppContainer because we
138+
have our own pill there for `lastFinished`. Resolve by keeping our hook
139+
shape and only adopting upstream's components where they don't depend
140+
on un-ported state.
141+
- **Port #3642** (`/tasks` command). Decision: replace `/bg list` with
142+
`/tasks`, or keep both and have `/bg` alias to `/tasks`?
143+
144+
Risk: TUI churn. Snapshot tests will break. Voice / recap state has to
145+
keep working in the same component tree.
146+
147+
Effort estimate: **medium**. One UI PR plus the slash-command PR.
148+
149+
### Phase C — agents survive session boundaries
150+
151+
The headline upstream feature.
152+
153+
- **Port #3739** (resume / continuation): persist enough agent state on
154+
disk so a freshly-started session can re-attach to running agents. Our
155+
`background-store.ts` already persists _that_ an agent ran; this PR
156+
extends it to the agent's transcript and pending tool calls.
157+
158+
Risk: this touches `chatRecordingService` and `sessionService`. Both
159+
have local divergence. Expect a careful merge.
160+
161+
Effort estimate: **large**. Likely the biggest single port left.
162+
163+
---
164+
165+
## 5. Cross-cutting concerns
166+
167+
### Settings
168+
169+
Upstream's bg-agent settings have grown into their own block. We already
170+
have an `agents.*` section (Arena/Team/Swarm) plus a flat `backgroundModel`.
171+
Before Phase A lands, decide whether to nest under `agents.background.*`
172+
or keep flat. **Recommendation:** nest, and migrate `backgroundModel` to
173+
`agents.background.model` with a back-compat read.
174+
175+
### Naming
176+
177+
We have **two** stop tools: `bg_stop` (shell) and `task_stop` (agent).
178+
Upstream is collapsing these. Pick a direction now so Phase A doesn't
179+
have to revisit it. **Recommendation:** keep the split until Phase A's
180+
`#3687` port forces the unification — premature consolidation rarely
181+
pays off in this codebase.
182+
183+
### Persistence layout
184+
185+
`~/.proto/agents/background.json` is shared by anything that wants to
186+
remember an agent existed. If Phase C extends it to full transcripts, we
187+
should move from a single JSON to a directory-of-files layout to avoid
188+
rewriting hundreds of KB on every checkpoint. **Recommendation:** keep
189+
the simple JSON until Phase C makes it actually painful.
190+
191+
### LiteLLM / gateway
192+
193+
All agent control surfaces assume the standard generate-content path.
194+
Our gateway layer has its own quirks (thinking-tag stripping, max_tokens
195+
ceilings). Validate Phase A against `protolabs/fast` and `protolabs/smart`
196+
before merging. **Recommendation:** add a smoke test that runs a
197+
background subagent with the gateway in CI.
198+
199+
---
200+
201+
## 6. Open questions for the team
202+
203+
1. **Do we need `/tasks` as a name, or is `/bg` good enough?** Aliasing
204+
is cheap; choosing the wrong primary name and renaming later is not.
205+
2. **Should the per-agent detail view be a dialog or a separate route?**
206+
Upstream picks dialog. Our DialogManager already has 8+ dialogs and
207+
is starting to feel crowded.
208+
3. **Cross-session resume scope:** do we attempt to resume _any_
209+
interrupted agent, or only those flagged as resumable? The latter is
210+
safer; the former is what the headline feature looks like.
211+
4. **SDK surface:** upstream's task-event SDK exposes a public API for
212+
third-party tools to subscribe. We have no SDK consumers today. Worth
213+
the maintenance cost to port the surface, or strip it on the way in?
214+
215+
---
216+
217+
## 7. Out of scope for this document
218+
219+
- Detailed code-level design for any single phase. That belongs in a
220+
follow-up doc per phase.
221+
- Performance work on the existing registry. Today's footprint is fine;
222+
revisit if Phase C's persistence changes that.
223+
- Anything about Arena, Team, or Swarm. Those are different agent
224+
systems that live alongside the background path; see
225+
`sub-agents-design.md`.
226+
227+
---
228+
229+
## Appendix: file inventory at time of writing
230+
231+
```
232+
packages/core/src/
233+
├── agents/
234+
│ ├── background-store.ts # 75 LOC, persistence
235+
│ ├── runtime/agent-headless.ts # headless execution
236+
│ └── runtime/agent-interactive.ts
237+
├── backgroundShells/
238+
│ ├── registry.ts # 126 LOC, central registry
239+
│ ├── watcher.ts # 109 LOC, lifecycle
240+
│ ├── diskOutput.ts # 125 LOC, file capture
241+
│ ├── notifications.ts # 54 LOC, completion
242+
│ └── types.ts # 44 LOC
243+
├── tools/
244+
│ ├── bg-stop.ts # 168 LOC, shell-level stop
245+
│ ├── task-stop.ts # agent-level stop
246+
│ └── shell.ts # is_background: true entry point
247+
└── utils/
248+
└── backgroundProgressEmitter.ts # 190 LOC, event bus
249+
250+
packages/cli/src/ui/
251+
├── commands/bgCommand.ts # 84 LOC, /bg list
252+
├── hooks/useBackgroundAgentProgress.ts # 127 LOC
253+
├── components/StatusBar.tsx # active-agent count
254+
└── AppContainer.tsx # lastFinished hit-limit warnings
255+
```
256+
257+
Last reviewed: 2026-05-02 (before Phase A planning).

0 commit comments

Comments
 (0)