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

# actor.agent@1 · OpenVibe.Services

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

# ActorAgent `actor.agent@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/actor/agent.v1.json`](/docs/contracts/actor.agent.json)

actor.agent@1: one of a person's agents as a contact (plan §12, A-1). An agent has a stable id and owner, a name and face, an optional TTS voice, the model it runs on (the OpenVibe runtime, the person's own keys, a free model on OpenVibe's GPU or their own Claude Code/Codex on a Link machine), the computer it uses (null when it has none, or one of Computer's kinds and placements), the connected apps it may use, its OpenVibe Memory scope (null when it keeps none), its approval level and when it was added. The default level is ask; money, passwords, deletions and sending to a new recipient always ask at every level, as a server-side floor.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `id` | string | yes | agt\_<ULID>, Actor's own id for the contact. Vibe, the first agent every person gets, is one of these. | - `pattern ^agt_[0-9A-HJKMNP-TV-Z]{26}$` |
| `owner` | string | yes | The person the contact belongs to (identity.subject-ref@1 in one column). Another person's agent is 404. | - `pattern ^user:usr_[0-9A-HJKMNP-TV-Z]{26}$` |
| `name` | string | yes |  | - `minLength 1`<br>- `maxLength 60` |
| `face` | string | yes | An avatar ref: an https image URL, a Media id, or a preset face such as preset:researcher. The UI draws it; Actor only stores and returns it. | - `minLength 1`<br>- `maxLength 500` |
| `voice` | string \| null | yes | A TTS voice id, or null when the agent has no voice. Voice calls are A-6; the field is stored now so a contact keeps its voice. | - `maxLength 80` |
| `model` | object | yes |  | - `no other fields` |
| `model.engine` | enum | yes | runtime: OpenVibe's own agent loop; own-keys: the person's provider keys through OpenVibe.AI; open-gpu: a free open model on OpenVibe's GPU; link: the person's own Claude Code or Codex on a Link machine. | - `one of "runtime", "own-keys", "open-gpu", "link"` |
| `model.model` | string | yes | The model id on that engine (a tier such as smart, a provider:model id, an open model name, or a harness name). | - `minLength 1`<br>- `maxLength 120` |
| `computer` | one of | yes |  |  |
| `apps` | array of string | yes | Connected app ids the agent may use (Connect's catalogue slugs). | - `maxItems 50`<br>- `unique items`<br>- `items: pattern ^[a-z][a-z0-9._-]{0,63}$` |
| `memory` | string \| null | yes | The OpenVibe Memory scope id this agent reads and writes, or null when it keeps no memory. | - `maxLength 100` |
| `level` | enum | yes | The approval level (plan §12): ask (the default) asks before every act; auto-edits lets the agent edit files and run its own work without asking; approve-for-me has a reviewer model of another family decide ordinary acts; full runs without asking. The floor still asks for money, passwords, deletions and sending to a new recipient at every level. | - `one of "ask", "auto-edits", "approve-for-me", "full"` |
| `created_at` | string | yes |  | - `format date-time` |

## Examples

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

 Valid: researcher

~~~~
{
  "id": "agt_01M4C49CW34NGX7TR2TNRVFWNY",
  "owner": "user:usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "name": "Researcher",
  "face": "https://openvibe.media/avatars/researcher.png",
  "voice": null,
  "model": {
    "engine": "own-keys",
    "model": "openai:gpt-5.1"
  },
  "computer": null,
  "apps": [],
  "memory": null,
  "level": "approve-for-me",
  "created_at": "2026-11-07T09:31:00.000Z"
}
~~~~

Valid: vibe

~~~~
{
  "id": "agt_01M4C49CW34NGX7TR2TNRVFWNW",
  "owner": "user:usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "name": "Vibe",
  "face": "preset:vibe",
  "voice": "ov-voice-aria",
  "model": {
    "engine": "runtime",
    "model": "smart"
  },
  "computer": {
    "kind": "kept-browser",
    "placement": "auto"
  },
  "apps": [
    "connect.github",
    "connect.slack"
  ],
  "memory": "mems_01M4C49CW7R8S9T0A1B2C3D4E5",
  "level": "ask",
  "created_at": "2026-11-07T09:30:00.000Z"
}
~~~~

Rejected: bad-level

~~~~
{
  "id": "agt_01M4C49CW34NGX7TR2TNRVFWNW",
  "owner": "user:usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "name": "Vibe",
  "face": "preset:vibe",
  "voice": null,
  "model": {
    "engine": "runtime",
    "model": "smart"
  },
  "computer": null,
  "apps": [],
  "memory": null,
  "level": "sometimes",
  "created_at": "2026-11-07T09:30:00.000Z"
}
~~~~

Rejected: missing-face

~~~~
{
  "id": "agt_01M4C49CW34NGX7TR2TNRVFWNW",
  "owner": "user:usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
  "name": "Vibe",
  "voice": null,
  "model": {
    "engine": "runtime",
    "model": "smart"
  },
  "computer": null,
  "apps": [],
  "memory": null,
  "level": "ask",
  "created_at": "2026-11-07T09:30:00.000Z"
}
~~~~

## Validate

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