---
title: "agents.approval@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/agents.approval"
updated: null
---

# agents.approval@1 · OpenVibe.Services

HTML: [agents.approval@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/agents.approval)

# AgentsApproval `agents.approval@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

- Version: 1.0.0
- Owner: actor
- Visibility: public
- Status: active
- Compatibility: backward
- Decision: [ADR-044](/docs/adr/ADR-044)
- Schema: [`https://openvibe.network/contracts/agents/approval.v1.json`](/docs/contracts/agents.approval.json)

agents.approval@1 (one agent system, 2026-11-12): a run stopped at a step to ask its person before it acts. WHAT is the act in plain words; OPTIONS are the answers the product offers, each with an id and the words a person reads; DECIDED\_BY and DECIDED\_AT are absent (or null) while it waits; ANSWER is the chosen option's id (or the person's own words, when the product allows them). Nothing the approval covers runs before the answer, and an answer decided once is never decided again. The approval is attached to the run's step (STEP\_SEQ), so a step log and an approval list line up. OpenVibe.Actor's approval inbox and OpenVibe.Codes' tool approvals are the same shape; the product keeps the grant.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `id` | string |  | The product's own approval id (apr\_…), when it has one; STEP\_SEQ is still the link to the run. | - `minLength 1`<br>- `maxLength 160` |
| `run_id` | string | yes |  | - `minLength 1`<br>- `maxLength 160` |
| `step_seq` | integer | yes | The seq of the run's step that asked (agents.step@1's seq). | - `minimum 1` |
| `what` | string | yes | The act in plain words, with its exact target: "post this to your feed", "run rm -rf build on your machine". Never a raw tool payload. | - `minLength 1`<br>- `maxLength 2000` |
| `options` | array of object | yes | The answers the product offers, in the order to show them. The floor categories (money, a password, a deletion, a new recipient) are asked every time and have no standing permission. | - `minItems 1`<br>- `maxItems 8`<br>- `items: no other fields` |
| `options[].id` | string | yes |  | - `minLength 1`<br>- `maxLength 80` |
| `options[].label` | string | yes |  | - `minLength 1`<br>- `maxLength 80` |
| `decided_by` | one of |  | Who answered: a person subject, a service or an agent. |  |
| `decided_at` | string \| null |  |  | - `format date-time` |
| `answer` | string \| null |  | The chosen option's id, or the person's own words when the product allows them. Null while it waits. | - `maxLength 2000` |

## Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

 Valid: approved

~~~~
{
  "id": "apr_01K9R2V6M8Q4T0B7C3D5E9F2GH",
  "run_id": "tsk_01K9R2V6M8Q4T0B7C3D5E9F2GH",
  "step_seq": 7,
  "what": "Push the branch and open a pull request on your machine's repository",
  "options": [
    {
      "id": "approve",
      "label": "Approve"
    },
    {
      "id": "decline",
      "label": "Decline"
    }
  ],
  "decided_by": {
    "type": "user",
    "id": "usr_01K9R2V6M8Q4T0B7C3D5E9F2GH"
  },
  "decided_at": "2026-11-12T10:01:00Z",
  "answer": "approve"
}
~~~~

Rejected: no-options

~~~~
{
  "run_id": "tsk_01K9R2V6M8Q4T0B7C3D5E9F2GH",
  "step_seq": 7,
  "what": "Post the answer to your feed",
  "options": []
}
~~~~

## Validate

~~~~
const contracts = require('openvibe-contracts');
contracts.validate('agents.approval@1', value);   // { valid, errors: [{ path, message }] }
~~~~
