# `subagent` API

[Documentation index](../README.md)

`subagent` is the structured model-facing API for Herdr-managed workers.

It has exactly five actions:

```text
list
assign
steer
reply
close
```

Unknown fields and unsupported field combinations fail with `invalid_request`.

The `subagent` tool is registered only for the root supervisor and authorized
managed parent controllers. Unmanaged sessions cannot invoke delegation or
obtain the managed worker inventory.

## Common request fields

| Field       | Type     | Meaning                                                                                                         |
| ----------- | -------- | --------------------------------------------------------------------------------------------------------------- |
| `action`    | string   | One of the five actions.                                                                                        |
| `agent`     | string   | Effective agent definition for a fresh assignment.                                                              |
| `label`     | string   | Public live worker identity or optional name/assertion during start/resume.                                     |
| `cwd`       | string   | Fresh working directory or saved-session cwd assertion.                                                         |
| `task`      | string   | Non-whitespace assignment text.                                                                                 |
| `files`     | string[] | Supporting files for assign, steer, or reply; text may be embedded, other files are canonical local references. |
| `reusable`  | boolean  | Keep the worker available after completion.                                                                     |
| `fork`      | string   | Exact Pi session path or full UUID used as fresh context source.                                                |
| `session`   | string   | Exact saved Pi session path or full UUID to resume/reuse.                                                       |
| `timeoutMs` | integer  | Explicit startup total budget.                                                                                  |
| `message`   | string   | `steer` or `reply` text.                                                                                        |

When supplied, string fields must contain non-whitespace text.

A label must match:

```text
^[a-z][a-z0-9_-]{0,31}$
```

## `list`

Request:

```json
{ "action": "list" }
```

No other fields are accepted.

Success:

```json
{
  "ok": true,
  "workers": [],
  "agent_definitions": []
}
```

A root sees the complete effective definition roster and workers visible through
its ownership boundary.

A managed parent sees only its allowed direct-child definitions and workers
visible through parent ownership. Disabled definitions remain in the root roster
with `enabled: false` but are omitted from a parent's definition list. Those
definition rows are leaf projections:
they omit child allowlists and effective `subagent` capability because a
parent-started child cannot delegate.

### Worker records

A visible worker record can include:

| Field                                            | Meaning                                                                                                           |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| `label`                                          | Exact live control label.                                                                                         |
| `state`                                          | Public safe-control state.                                                                                        |
| `steerable`                                      | Independent steering eligibility.                                                                                 |
| `workspace_id`, `pane_id`, `tab_id`, `tab_label` | Herdr evidence.                                                                                                   |
| `cwd`                                            | Worker working directory.                                                                                         |
| `pi_session_id`, `pi_session_path`               | Pi session correlation.                                                                                           |
| `owner_session_id`                               | Exact direct owner Pi session.                                                                                    |
| `agent_definition`                               | Effective definition name used by the worker.                                                                     |
| `model`, `thinking`                              | Best available live metadata.                                                                                     |
| `active_request_id`                              | Active assignment request when present.                                                                           |
| `last_activity_at`                               | Last durable Pi-observed activity timestamp when known.                                                           |
| `stale`, `inactive_ms`                           | Advisory inactivity fields for qualifying `working` workers.                                                      |
| `parent_label`                                   | Visible direct parent label when applicable.                                                                      |
| `orphan`                                         | Proven orphan recovery projection when applicable.                                                                |
| `cleanup_error`                                  | Cleanup or delivery evidence that needs attention.                                                                |
| `result_error`                                   | Correlated result-persistence failure requiring mailbox recovery before reassignment.                              |
| `recovery_only`                                  | Marks a record retained for recovery visibility and not eligible for control.                                     |
| `diagnostic`                                     | Bounded mailbox-state diagnostic on a non-actionable `unknown` record; included only in a root supervisor's list. |
| `tokens`                                         | Herdr/Pi presentation metadata.                                                                                   |

Physical identity fields are evidence. Use `label` for live control.

Plain/model list output preserves normal root/direct-child grouping. Records
whose parent is absent or whose ancestry is incomplete appear in an
`Unmatched ancestry (recovery only)` section with their available identity and
are marked non-actionable; their reported worker count still includes them.
Workers left unresolved because of cyclic ancestry are also included there with
`state: "unknown"`, `steerable: false`, and a bounded cycle diagnostic.

### Agent-definition metadata

Definition metadata can include:

- `name`
- `extensionSource`
- `overrideSource`
- `enabled` when the effective definition is disabled
- `description`
- `model`
- `thinking`
- `noTools`
- `noBuiltinTools`
- `tools`
- `excludeTools`
- `noSkills`
- `inheritSkills`
- `skills`
- `subagents`

This metadata is deterministic declared policy, not a runtime capability probe
or a complete inventory of launch arguments. It reports the policy fields above
but intentionally does not include `extensions`, `noExtensions`, context-file
inheritance, system-prompt/body composition, or effective body provenance.
Parent-visible metadata is the declared leaf policy after removing delegation
capability. Managed workers additionally retain the mandatory `ask_owner`
infrastructure tool even when ordinary tool policy is restrictive; that tool
is not represented in this metadata.

An omitted `enabled` field is effective `true`.

## `assign`: fresh definition

Required:

```json
{
  "action": "assign",
  "agent": "implementer",
  "task": "Implement the approved change"
}
```

Allowed fields:

```text
action
agent
label
cwd
task
files
reusable
fork
timeoutMs
```

No `session` or `message`.

Without `fork`, Pi starts a fresh session.

With `fork`, the exact saved Pi session path or full UUID is used as explicit
context source. The current supervisor session is never an implicit fork source.

`cwd` defaults to the controller's current working directory for a fresh worker.

`reusable: true` keeps the worker available after result delivery.

Fresh assignment rejects a definition with `enabled: false` before worker
lifecycle mutation. The error points to `/subagents overrides` or another
enabled definition. An enabled parent must also reference only enabled children
in `subagents`; a parent referencing a disabled child can remain discoverable,
but is rejected during assignment or fresh worker startup with an explicit
disabled-child validation error.

Success includes:

```json
{
  "ok": true,
  "action": "assign",
  "label": "implementer",
  "pane_id": "...",
  "session_id": "...",
  "request_id": "..."
}
```

`pane_id` is startup evidence, not a later control target.

## `assign`: historical session

Required:

```json
{
  "action": "assign",
  "session": "<exact .jsonl path or full UUID>",
  "task": "Continue the investigation"
}
```

Allowed fields:

```text
action
session
label
cwd
task
files
reusable
timeoutMs
```

No `agent`, `fork`, or `message`.

The saved session's history/tree, cwd, and agent-definition name are restored or
resolved. An optional `cwd` must resolve to the saved cwd. The current effective
definition and explicit current launch flags supply runtime configuration for a
non-live historical resume; saved model/thinking values are fallback state when
the current launch does not explicitly set them.

When exactly one directly owned live worker already represents the session, the
existing worker is reused and must be `ready`.

When it is not live, Pi Herd resolves the saved definition name against the
current effective roster and restores the exact saved session. A live reusable
assignment is different: it reuses the existing worker's frozen launch
configuration and does not rebuild it from current definitions.

Non-live historical restores reject a currently disabled definition. When the
saved session already has exactly one matching live worker, the worker is reused
even if its definition is now disabled, preserving its launch-time configuration.

An explicit `reusable` cannot change the lifetime policy of an already-live
worker.

## `assign`: live reusable worker

Required:

```json
{
  "action": "assign",
  "label": "worker",
  "task": "Perform the next phase"
}
```

Allowed fields are only:

```text
action
label
task
files
```

The worker must report `state: "ready"`.

This does not rebuild the worker's launch-time model, tools, extensions, skills,
or system prompt.

## `files`

`files` is valid on `assign`, `steer`, and `reply` (not `list` or `close`).

Paths are resolved from the controller cwd, validated as readable regular files,
and canonicalized with `realpath`. Complete strict UTF-8 text is embedded when
it fits; other files remain canonical local references and are not copied.

First canonical occurrence wins.

See [Handoffs and files](../guides/handoffs.md).

## `timeoutMs`

`timeoutMs` is valid on fresh-agent and historical-session assignments.

Explicit values must be integers from:

```text
5001 through 300000
```

The total budget reserves 2000 ms for one bounded startup diagnostic read.

When omitted, the current implementation uses a 302000 ms total default
(300000 ms child budget plus 2000 ms diagnostic reserve).

## `steer`

Request:

```json
{
  "action": "steer",
  "label": "implementer",
  "message": "Also update the focused regression.",
  "files": [".pi-herd/review.md"]
}
```

`files` is optional supporting evidence; complete strict UTF-8 text is embedded
when it fits, and other files are canonical local references.

The worker must have an active assignment and its list record must report
`steerable: true`.

Success includes the new steer request ID, current session ID, and original
assignment request ID.

Steering changes the current assignment and does not create another final
assignment result.

The worker may apply a steer before acknowledgement persistence, so retry at the
steer boundary is at-least-once.

## `reply`

Request:

```json
{
  "action": "reply",
  "label": "worker",
  "message": "Use option B.",
  "files": [".pi-herd/decision.md"]
}
```

`files` is optional supporting evidence with the same inline/reference rules.

The exact worker must have one valid outstanding `ask_owner` record correlated
to its current assignment and immutable worker identity.

Success includes:

- `request_id`
- `ask_id`
- `assignment_request_id`
- `session_id`

The reply resumes the same assignment.

See [`ask_owner` API](ask-owner.md).

## `close`

Request:

```json
{
  "action": "close",
  "label": "worker"
}
```

Only `action` and `label` are accepted.

The label must identify exactly one directly owned managed worker, unless the
root supervisor is performing narrow, evidence-backed orphan recovery after
the former parent is proven absent.

Closing abandons a pending owner question. Closing a parent cascades through
directly owned children first.

Cleanup remains fail-closed when exact ownership, or the root-only proven
orphan-recovery condition, cannot be proved. Managed parents cannot use orphan
recovery to close workers outside their direct ownership.

## Result delivery

An accepted assignment has one correlated final result.

Worker completion is delivered to the exact owning Pi session. Model-visible
content begins with a compact envelope containing the exact `label`, `agent`,
`request`, and `status`. Completion details can include:

- `requestId`
- `workerLabel` (the exact label)
- `agentDefinition` (the separate definition name)
- status
- elapsed time
- context usage
- truncation status
- `resultPath`
- full-output path when bounded output overflow is persisted
- persistence error when output could not be saved
- worker error when the assignment failed

Result delivery, not raw process idleness, gates worker reuse.

## Errors

Tool failures return structured details rather than throwing an unstructured
model-visible exception for normal public errors.

See [Errors](errors.md).

## See also

- [Worker states](worker-states.md)
- [Workers and identity](../concepts/workers.md)
- [Recovery](../guides/recovery.md)
