subagent-request-approval · git:20260922.794a6b2 · 2026-09-22 · sha256 6e00ec6288a33fdb

subagent-request-approval git:20260922.794a6b2A

Immutable. This exact content never changes and is served at /api/v1/blob/6e00ec6288a33fdb.

---
name: subagent-request-approval
description: Use when a T3 command was blocked or a predictable ordered T3 set must be requested before execution
---

# Request Approval — Producer Branch

## Plan-first set

After read-only investigation, collect every predictable exact T3 command that
forms one coherent bounded operation -- one command or several. Do not attempt
the commands first, even a single one: request it proactively through the
same verb.

Run one CLI request, with one `--command` per atomic item in execution order:

```
gaia approvals request-set --command '<exact 0>' --command '<exact 1>' --rationale '<goal, risk>' --verification '<check to run after>' --rollback '<how to undo>' --agent-id <agent_id> [--session-id <session_id>]
```

A single predictable T3 command uses the identical verb with one `--command`.

`--session-id` is optional, and the same rule governs `request-file-write`:
pass it only when the dispatch handed you a session id; never invent one, and
never guess one. Omitted, the row is born without an owner and the first host
session that presents it adopts it, in the same write as the SHOWN event
(`bin/cli/approvals.py::cmd_opencode_present`); from then on every other
session is refused. A dispatched OpenCode agent has no way to learn its own
session id -- the plugin exports nothing but `GAIA_DISPATCH_AGENT` into its
shell -- so omitting the flag is the normal case there. A wrong value is worse
than none: an approval owned by a session that will never present it cannot be
presented by anyone, and dies pending with a single REQUESTED event.

The CLI validates T3 eligibility, persists REQUESTED, and returns `status`, the
canonical `approval_id`, and `command_set` with each command fingerprint. Relay
those values inside `approval_request`; do not calculate an id or fingerprint.
The order-sensitive `request_fingerprint` is persisted but not returned by this
command; when it is needed, read the pending back with `gaia approvals list
--json` and match the full canonical id.

## Blocked single command

When the pre-execution policy gate returns `[T3_BLOCKED]`, stop. Copy the
returned `approval_id` and sealed payload verbatim into `approval_request`. Do
not retry, reword, split, wrap, or seek the same effect through another tool.

## Checkpoint and stop

1. Set `agent_state` to `APPROVAL_REQUEST`.
2. Put all exact consent data in `approval_request`, including full ordered set,
   risk, rollback, and verification when COMMAND_SET.
3. Add only the block/request outcome to evidence; do not duplicate payloads.
4. Set `pending_steps` to execution after consent and `next_action` to relay the
   request to the user.
5. Finalize the non-terminal contract and stop; the persisted row is the delivery.

The producer does not present an approval as already granted and does not verify
execution before it happens. `orchestrator-present-approval` selects the host
modality and presents consent; `execution` owns post-grant execution.

## Grouping boundary

Use a set only for exact commands already implied by the accepted plan, with
one risk/rollback/verification narrative. Do not group unrelated effects,
alternatives, speculative cleanup, or commands derived from earlier outputs.
Consent grouping is not atomic execution.

For continuation after a failed set, follow `command-execution` for the
execution-time stop and `agent-protocol` for consumer reconciliation. This
skill constructs the new exact request that reconciliation identifies.