# `Pixir.Subagents`
[🔗](https://github.com/Ranvier-Technologies/pixir/blob/main/lib/pixir/subagents.ex#L1)

Public facade for BEAM-native Subagent orchestration (ADR 0011).

Subagents move through a small lifecycle state machine. The usual path is
`queued -> running -> completed`, but failures, timeouts, cancellation, and
detached restored children must remain explicit so parents and diagnostics can
tell "finished cleanly" apart from "needs operator attention".

A warm child keeps its copied replay Events as historical evidence. Its live
authorization posture is the session-scoped posture written immediately after
the most recent valid runtime lineage boundary; cold resume evaluates posture
and mutation evidence only in that boundary's current segment. Logs without a
valid boundary retain the legacy root/child/Fork fold rules.

`max_depth` is an absolute delegation-depth cap from the root Session. A child
spawned by the root runs at depth `1`; that child may only spawn another child
when the configured cap is at least `2`.

# `child_spec`

Application child spec.

# `close`

Cancel a running Subagent, or close a queued/terminal Subagent as cleanup.

Cancelling a running Subagent fences its active logical Turn without stopping the
reusable child Session. It then appends a `cancelled_by_parent` `:subagent_event`
with `scope: "turn"` to the child's own Log. The event follows the synchronous
interrupt result, but a C6-classified late declaration may append after it, so it is
not promised physically list-last. Callers that cancel on behalf of a Workflow may
name the canceller with `:workflow_id`, `:workflow_step_id`, and
`:workflow_close_outcome`; those fields are simply absent from the child event for a
plain parent close. Running-close results include bounded `cancellation_evidence`;
the ordinary path is `complete`, while missing durable Session/child evidence is
`partial` without raw errors or exits. The existing lifecycle return fields remain.

# `default_limits`

Default runtime limits.

# `diagnostics`

Return a runtime diagnostics projection for one parent Session.

Diagnostics idempotently hydrates restorable parent state from durable evidence before
projecting the snapshot. Hydration may reattach live children: it subscribes to child
event buses through `Pixir.Events` and rearms child timeout timers. It may also fold the
parent Log after a Manager restart, but it does not write canonical events. The returned
data remains volatile process-health evidence; use the Session Log and Session tree for
canonical lifecycle facts.

# `list`

List Subagents for a parent Session.

# `reconstruct`

Reconstruct Subagent relationships and terminal state from parent History.

# `restrict_resume_posture`

```elixir
@spec restrict_resume_posture(map() | nil, Pixir.Permissions.mode(), map() | nil) ::
  {:ok, map() | nil} | {:error, map()}
```

Apply the common restrict-never-widen rules to a restored posture.

# `resume_posture`

```elixir
@spec resume_posture(
  String.t(),
  keyword()
) :: {:ok, map()} | {:error, map()}
```

Rehydrate a Session's durable permission posture for a cold resume.

Root Sessions record their posture at creation (`Pixir.Conversation.start/1`,
lineage `root`, trusted only in root position: first non-`session_fork` event,
runtime-authored source) and restore the recorded capability ceiling —
including unbounded auto when the marker declared it. Spawned children record
theirs with lineage `child` and keep the stricter contract: write-capable
history restores only with a bounded policy.

Warm-start Logs add a runtime-authored `lineage_boundary_v1` marker. Only the
permission posture and mutation evidence physically appended after the last
valid marker govern that live warm segment; copied posture remains replay
evidence. A valid boundary without current posture fails closed. Without a
valid boundary, the existing full-history root/child/Fork behavior is
preserved. Legacy Logs without posture evidence remain resumable only when
they contain no write-capable evidence, and then restore an explicit read-only
ceiling; otherwise they fail closed with reason `missing`, which is the one
classification the operator may override via the CLI's explicit legacy-root
attestation (never as unbounded auto).

# `send_input`

Send follow-up input to an idle Subagent.

# `spawn_agent`

Spawn or queue a Subagent.

# `statuses`

All known Subagent lifecycle statuses.

# `summarize`

Summarize agent maps for model-facing output.

# `summarize_wait_outcome`

Build model-facing text for a structured wait outcome.

# `terminal?`

Whether a status is terminal.

# `terminal_statuses`

Statuses that no longer have a live child runtime.

# `transition_allowed?`

Whether the public lifecycle contract allows a status transition.

`closed` is retained as Pixir's local close/cleanup state. Completed, failed,
timed-out, and cancelled Subagents may be restarted by `send_input/4`; detached
children cannot be resumed because there is no live process handle.

# `validate_spawn`

Validate and normalize a Subagent spawn without creating runtime state.

# `wait`

Wait for selected Subagents to reach a terminal status.

# `wait_outcome`

Wait for selected Subagents and return a structured outcome.

Unlike `wait/4`, this keeps partial fanout visible: timed-out, failed, detached,
cancelled, and still-incomplete children are bucketed instead of turning the
parent tool call into an opaque failure. The returned `"partial"` boolean is
true for any non-completed aggregate status; consumers should use `"status"`
when they need to distinguish `"partial"` from `"incomplete"`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
