Harness spec 3.4.0: progress phases, and subagents v2 — the main agent and its tree
ci / check (push) Waiting to run

progress.md: thirteen fixed phases (queued … failed), each { phase, since, data },
their texts as shared i18n keys (loop.json progress), one line every client draws,
sent beside the old status text in /api/v2 and over the link (capability progress).

subagents.md §5–§13 (supersedes team.md where they differ): only the main agent
adds, assigns, replaces, stops and decides; sub-managers direct those placed under
them; ids, positions, parents; Min above 1 opens slots; permissions inherited and
never widened, request options decided by the main agent, what nobody in the tree
can allow goes to the person; team_finish, findings, running out of context;
transcripts read-only; the tree over the link (capability tree). New tools
team_whoami, team_finish, team_findings, team_request, team_decide, team_assign,
team_replace. Conformance: progress, delegation; team updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
HomerandClaude Opus 5.5 committed 2026-11-10 08:10:36 +00:00
1 parent 6a0e0ed145
commit 4b8786b7f6
26 files changed
+1844 -97

No files matched your search

+31 -4
View File
@@ -14,7 +14,7 @@
"cli": [],
"llembas": []
},
"description": "Add a member to your team and start it at once, in the background, on its part of the work. You lead: members do the work while you plan, coordinate and review — once you have a member, tools that change things are refused to you.\n\n- `name` is how everyone addresses it: lowercase letters, digits and hyphens, after what it owns (`parser`, `api-tests`), unique in the team.\n- `role` is one line: what it owns. `task` is its brief and must stand on its own — it sees nothing of this conversation: what to do, when it is done, and what to report.\n- `goal` is the team's goal in a line; your first member needs it, and every member is told it.\n- `lead: true` lets it add members of its own and lead an area; it then manages as you do.\n- The person sets how many agents the team may have, you included; past that this is refused. When the model is already serving as many requests as it can at once, the member waits for a slot and starts when one frees.\n- Its final reply comes to you as its report. Meanwhile team_send messages it, team_read shows the team and the room, team_stop stops it.\n- Agents: {{agents}}",
"description": "Add a subagent and start it at once, in the background, on its part of the work. Only you, the main agent, add subagents. You lead: subagents do the work while you plan, coordinate and review — once you have one, tools that change things are refused to you.\n\n- `name` is how everyone addresses it: lowercase letters, digits and hyphens, after what it owns (`parser`, `api-tests`). `role` is its position, one line: what it owns. `task` is its brief and must stand on its own — it sees nothing of this conversation: what to do, when it is done, and what to report.\n- `goal` is the team's goal in a line; your first subagent needs it, and every subagent is told it.\n- `lead: true` makes it a sub-manager: it directs the subagents you place under it (`parent`), reviews their reports and reports to you; it does not add or stop subagents itself.\n- `mode` is its permission mode: its parent's by default, never looser. With a stricter mode you may give `request` options — kinds of action (read, write, execute) it may ask you for with team_request; you decide with team_decide.\n- The person sets how many agents the team may have, you included; past that this is refused. When the model is already serving as many requests as it can at once, the subagent waits for a slot and starts when one frees.\n- It reports with team_finish (or its final reply). Meanwhile team_send messages it, team_read shows the tree and the room, team_assign gives it new work, team_replace replaces it, team_stop stops it.\n- Agents: {{agents}}",
"parameters": {
"type": "object",
"properties": {
@@ -26,7 +26,7 @@
"role": {
"type": "string",
"minLength": 1,
"description": "One line: what it owns"
"description": "Its position, one line: what it owns"
},
"task": {
"type": "string",
@@ -39,7 +39,7 @@
},
"lead": {
"type": "boolean",
"description": "May add members of its own and lead an area (default: false)"
"description": "A sub-manager: directs the subagents placed under it (default: false)"
},
"agent": {
"type": "string",
@@ -48,6 +48,32 @@
"model": {
"type": "string",
"description": "Run it on another model — only one the person named in this conversation (its id or name, as in the list in your instructions). Default: the session's model."
},
"parent": {
"type": "string",
"description": "The sub-manager to place it under (default: you, lead)"
},
"mode": {
"type": "string",
"enum": [
"auto",
"edit",
"manual",
"plan"
],
"description": "Its permission mode: its parent's or stricter (default: its parent's)"
},
"request": {
"type": "array",
"items": {
"type": "string",
"enum": [
"read",
"write",
"execute"
]
},
"description": "With a stricter mode only: kinds of action it may ask you for (team_request)"
}
},
"required": [
@@ -58,5 +84,6 @@
},
"variables": {
"agents": "the agents a member may be: `name — description`, separated by \"; \" (as task's)"
}
},
"offered": "main"
}
+51
View File
@@ -0,0 +1,51 @@
{
"name": "team_assign",
"scope": "shared",
"sessions": "both",
"risk": "interact",
"exclusive": false,
"block": "tool",
"purpose": false,
"requires": [
"team"
],
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
"aliases": {
"cli": [],
"llembas": []
},
"offered": "main",
"description": "Give a subagent that has not ended a new task: it is told at its next step, or woken. Optionally a new position (`role`), another sub-manager to work under (`parent`, or lead), or a stricter `mode`.",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"task": {
"type": "string",
"minLength": 1
},
"role": {
"type": "string"
},
"parent": {
"type": "string"
},
"mode": {
"type": "string",
"enum": [
"auto",
"edit",
"manual",
"plan"
]
}
},
"required": [
"name",
"task"
]
}
}
+38
View File
@@ -0,0 +1,38 @@
{
"name": "team_decide",
"scope": "shared",
"sessions": "both",
"risk": "interact",
"exclusive": false,
"block": "tool",
"purpose": false,
"requires": [
"team"
],
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
"aliases": {
"cli": [],
"llembas": []
},
"offered": "main",
"description": "Decide a subagent's request (team_request): allow it or refuse it, with a note it is told. You may allow only what your own mode would allow you; anything beyond that goes to the person when the subagent tries.",
"parameters": {
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"allow": {
"type": "boolean"
},
"note": {
"type": "string"
}
},
"required": [
"id",
"allow"
]
}
}
+41
View File
@@ -0,0 +1,41 @@
{
"name": "team_findings",
"scope": "shared",
"sessions": "both",
"risk": "interact",
"exclusive": false,
"block": "tool",
"purpose": false,
"requires": [
"team"
],
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
"aliases": {
"cli": [],
"llembas": []
},
"description": "Findings kept beyond your context: `write` adds one (a fact, a result, where something is) to yours; `read` shows yours, or with `of` those of a subagent under you (the main agent: anyone's), ended ones included. Write as you go: when your context fills you have one turn left, and your findings are what the next agent starts from.",
"parameters": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"write",
"read"
]
},
"text": {
"type": "string",
"description": "write: the finding"
},
"of": {
"type": "string",
"description": "read: a name or an id (default: yours)"
}
},
"required": [
"action"
]
}
}
+31
View File
@@ -0,0 +1,31 @@
{
"name": "team_finish",
"scope": "shared",
"sessions": "both",
"risk": "interact",
"exclusive": false,
"block": "tool",
"purpose": false,
"requires": [
"team"
],
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
"aliases": {
"cli": [],
"llembas": []
},
"offered": "subagent",
"description": "Your task is done: send your report to your parent and end. Make the report complete on its own — the result, then the evidence (file:line), then anything you could not settle. Save anything worth keeping beyond the report with team_findings first. Nothing runs after this call.",
"parameters": {
"type": "object",
"properties": {
"report": {
"type": "string",
"minLength": 1
}
},
"required": [
"report"
]
}
}
+1 -1
View File
@@ -14,7 +14,7 @@
"cli": [],
"llembas": []
},
"description": "The team and its room: every agent (name, role, who leads it, state, model, last activity), and the room's messages after `since` that are yours to see — those you sent or received and those of the members under you; the lead sees them all. Messages are numbered: pass the last number you saw as `since` to read only what is new.",
"description": "The tree and its room: every agent (name, id, position, parent, state, model, mode, context use, last activity), open slots, subagents that have ended, and the room's messages after `since` that are yours to see — those you sent or received and those of the subagents under you; the main agent sees them all. Messages are numbered: pass the last number you saw as `since` to read only what is new.",
"parameters": {
"type": "object",
"properties": {
+34
View File
@@ -0,0 +1,34 @@
{
"name": "team_replace",
"scope": "shared",
"sessions": "both",
"risk": "interact",
"exclusive": false,
"block": "task",
"purpose": false,
"requires": [
"team"
],
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
"aliases": {
"cli": [],
"llembas": []
},
"offered": "main",
"description": "Replace a subagent — one that ran out of context, or one that is stuck: it ends (stopped, if it has not already), and a new one with the same name, position, parent, mode and model takes its place, briefed with `task` (default: the old task) and the old one's findings. The subagents under it move under the new one.",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"task": {
"type": "string"
}
},
"required": [
"name"
]
}
}
+41
View File
@@ -0,0 +1,41 @@
{
"name": "team_request",
"scope": "shared",
"sessions": "both",
"risk": "interact",
"exclusive": false,
"block": "tool",
"purpose": false,
"requires": [
"team"
],
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
"aliases": {
"cli": [],
"llembas": []
},
"offered": "subagent",
"description": "Ask the main agent to allow a call your mode does not, of a kind your request options name. Say the tool, the permission pattern you need (a command such as `git push *`, or a path) and why. Its decision comes to you as a message; once allowed, make the call again.",
"parameters": {
"type": "object",
"properties": {
"tool": {
"type": "string",
"minLength": 1
},
"pattern": {
"type": "string",
"minLength": 1
},
"why": {
"type": "string",
"minLength": 1
}
},
"required": [
"tool",
"pattern",
"why"
]
}
}
+2 -2
View File
@@ -14,7 +14,7 @@
"cli": [],
"llembas": []
},
"description": "Send a message through your team's room: to one or more agents by name, or to `all`. It reaches each at its next step, or wakes one that has finished, its context intact. Message the agent who owns a thing; use `all` only for what everyone needs. The team's lead is `lead`; your manager is reached by its name.",
"description": "Send a message through the team's room: to one or more agents by name, to `parent` (the agent you report to), or to `all`. It reaches each at its next step, or wakes one that has finished, its context intact. Message the agent who owns a thing; use `all` only for what everyone needs. The main agent is `lead`.",
"parameters": {
"type": "object",
"properties": {
@@ -24,7 +24,7 @@
"type": "string"
},
"minItems": 1,
"description": "Names, or [\"all\"]"
"description": "Names, [\"parent\"], or [\"all\"]"
},
"message": {
"type": "string",
+4 -3
View File
@@ -14,18 +14,19 @@
"cli": [],
"llembas": []
},
"description": "Stop a member of your team, and the members under it, where they are: their work stops and they leave the team, which makes room for others. Only members under you, directly or through your members; `all` stops every one of them. Nothing they had not reported comes back — ask for a report with team_send first when you need it.",
"description": "Stop a subagent, and the subagents under it, where they are: their work stops and they end, which makes room for others. Only you, the main agent, stop subagents; `all` stops every one. Nothing they had not reported comes back — ask for a report with team_send first, or read their findings with team_findings.",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"description": "A member under you, or all"
"description": "A subagent's name, or all"
}
},
"required": [
"name"
]
}
},
"offered": "main"
}
+22
View File
@@ -0,0 +1,22 @@
{
"name": "team_whoami",
"scope": "shared",
"sessions": "both",
"risk": "read",
"exclusive": false,
"block": "tool",
"purpose": false,
"requires": [
"team"
],
"unavailable": "The person allows one agent in this chat: there is no team. Do the work yourself.",
"aliases": {
"cli": [],
"llembas": []
},
"description": "Who you are on the team: your id, name, position, parent, task, permission mode and request options, model, limits, and how full your context is.",
"parameters": {
"type": "object",
"properties": {}
}
}