Subagents in the CLI (harness spec 3.3.0): the model, capacity, the offer, /context
ci / check (push) Waiting to run

- A task subagent or a team member runs on the session's model unless the
  person named another in this session's own messages (team/subagents.ts;
  engine.personSaid reads every prompt and mid-turn message, compacted ones
  included). Not named: refused; an agent file's own model is not used.
- Another model on the session's one-model server is refused; a one-request
  session model is not its own subagent, and nothing else is picked.
- The team is offered when a model could serve: the session's with two
  slots, or any usable model off its one-model server; the size note adds
  team_own when the session's model cannot serve its own.
- "Subagents" in /effort, /team, /settings and the config schema; the status
  bar reads "agents 3/4 · 2 subagents working".
- /context: used of the window, one bar by category, each category's share,
  what is free, and "N until auto-compact".
- Conformance runner for the subagents area (26 cases); helper -> task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
HomerandClaude Opus 5.5 committed 2026-11-09 17:04:58 +00:00
1 parent a26dd8a5e0
commit 6e0582dc22
21 files changed
+401 -104

No files matched your search

+6 -6
View File
@@ -197,7 +197,7 @@ describe("background subagents (spec 2.0.0)", () => {
],
[{ chunks: [toolCall(0, "r1", "read", '{"path":"calc.py"}')] }, { chunks: [delta({ content: "calc.py:2 divides by len(v) - 1." })] }],
)
await a.turns.prompt("look into it in the background")
await a.turns.prompt("look into it in the background (subagents on g/m or g/n)")
const started = fake!.requests[1].messages.at(-1).content as string
expect(started).toStartWith("[#0001]\nStarted subagent explore as job1 (find the bug).")
await settled(a, 3)
@@ -233,7 +233,7 @@ describe("background subagents (spec 2.0.0)", () => {
{ chunks: [delta({ content: "Second report." })] },
],
)
await a.turns.prompt("go")
await a.turns.prompt("go (subagents on g/m or g/n)")
expect(fake!.requests[2].messages.at(-1).content).toContain("Sent to job1")
await settled(a, 6)
const child = other!.requests
@@ -252,7 +252,7 @@ describe("background subagents (spec 2.0.0)", () => {
[{ chunks: [toolCall(0, "t1", "task", JSON.stringify({ description: "find loaders", prompt: "Find the loaders", model: "g/m" }))] }, { chunks: [delta({ content: "Thanks." })] }],
[{ chunks: [toolCall(0, "p1", "report", JSON.stringify({ text: "There are two loaders; which one?" }))] }, { chunks: [delta({ content: "Final: the YAML one." })] }],
)
await a.turns.prompt("go")
await a.turns.prompt("go (subagents on g/m or g/n)")
const msgs = fake!.requests[1].messages
const note = msgs.find((m: any) => m.role === "user" && String(m.content).startsWith(MARKS.message))
expect(note?.content).toContain("job1 (explore: find loaders):\nThere are two loaders; which one?")
@@ -278,7 +278,7 @@ describe("background subagents (spec 2.0.0)", () => {
[{ chunks: [toolCall(0, "b1", "bash", JSON.stringify({ command: "true", description: "nothing" }))] }, { chunks: [delta({ content: "ran" })] }],
{ asker },
)
await a.turns.prompt("go")
await a.turns.prompt("go (subagents on g/m or g/n)")
expect(seen).toEqual([{ jobId: "job1", agent: "general", description: "run it" }])
})
@@ -297,7 +297,7 @@ describe("background subagents (spec 2.0.0)", () => {
[{ chunks: [delta({ content: "slow" })], gapMs: 400 }],
{ oneAtATime: true },
)
await a.turns.prompt("go")
await a.turns.prompt("go (subagents on g/m or g/n)")
const results = fake!.requests[1].messages.filter((m: any) => m.role === "tool").map((m: any) => m.content as string)
expect(results[0]).toStartWith("[#0001]\nStarted subagent explore as job1")
expect(results[1]).toContain("holds one model at a time, and a subagent is already running on g/m there")
@@ -330,7 +330,7 @@ test("a cancelled worktree subagent keeps its branch, and the result names it",
const root = a.project.root
for (const args of [["init", "-q", "-b", "main"], ["config", "user.email", "t@e"], ["config", "user.name", "T"], ["config", "commit.gpgsign", "false"], ["add", "calc.py"], ["commit", "-q", "-m", "init"]]) git(root, args)
;(a.project as any).gitRoot = root
const turn = a.turns.prompt("fix it in a worktree")
const turn = a.turns.prompt("fix it in a worktree (subagents on g/m or g/n)")
const until = Date.now() + 8000
while (Date.now() < until && !events.some((e) => e.type === "sub_tool" && e.name === "write")) await Bun.sleep(20)
const write = events.find((e) => e.type === "sub_tool" && e.name === "write")