ActorVoice actor.voice@1

Generated at from openvibe-contracts v0.419.0 and openvibe-sdk v0.161.0.

Version
1.0.0
Owner
actor
Visibility
public
Status
active
Compatibility
backward
Decision
ADR-044
Schema
https://openvibe.network/contracts/actor/voice.v1.json

actor.voice@1: an agent's voice and nothing else — the small document a person hands to somebody else so their agent speaks in the same house voice. It carries the agent's name, a short bio, its instructions (the house voice it speaks in), the rules it keeps, its default approval level, the model it prefers and the connected apps it may use (ids only, never a key), an optional face (an avatar ref), an optional author, and an integrity block. It never carries memory, a connector's token or a file: a voice is a voice, not a person. The INTEGRITY block is a sha256 over the canonical JSON of the document: it shows the file was not edited after it was written, and it says nothing about who wrote it — anyone can write a file that names an author and compute its hash. The AUTHOR is therefore a claim, not a fact: a document may name anyone, and whoever reads it must say so (it says it was made by …; that is not checked). Only the service that owns the agent may vouch for who wrote a voice, and it does so by sharing it itself. The canonical JSON is the document's own fields, in this order and with these names: voice, name, bio, face, instructions, rules, level, model, apps, author; an optional field that is absent or empty is left out, author is { subject } or { subject, name }, and the value is the compact JSON of that object (no spaces). CREATED_AT is when the document was written; it is not part of the hash. Importing a voice makes a new agent at level ask whatever the file says: a borrowed agent starts cautious, and the person raises it themselves.

Fields

FieldTypeRequiredDescriptionConstraints
voiceconstyesThe document marker. This is the agent's voice, not a TTS voice id.
  • = "actor.voice@1"
namestringyesThe agent's name.
  • minLength 1
  • maxLength 60
biostringA short bio: one or two lines on what this agent is for.
  • maxLength 280
facestringAn avatar ref: an https image URL, a Media id, or a preset face such as preset:researcher.
  • maxLength 500
instructionsstringyesThe house voice the agent speaks in: what it does, how it says it, what it never does.
  • minLength 1
  • maxLength 4000
rulesarray of stringThe rules it keeps, one line each.
  • maxItems 20
  • items: minLength 1
  • items: maxLength 200
levelenumyesThe approval level it works at (actor.agent@1's levels). The default is ask; an import always starts at ask.
  • one of "ask", "auto-edits", "approve-for-me", "full"
modelobjectThe model it prefers, by id. Never a key: the key stays in OpenVibe.AI's vault.
  • no other fields
model.engineenumyes
  • one of "runtime", "own-keys", "open-gpu", "link"
model.modelstringyes
  • minLength 1
  • maxLength 120
appsarray of stringThe connected app ids it may use (Connect's catalogue slugs). Ids only: a token is never here.
  • maxItems 50
  • unique items
  • items: pattern ^[a-z][a-z0-9._-]{0,63}$
authorobjectWho the document says it is from. A claim, not a fact: a file may name anyone, and the hash says nothing about it. A service that owns the agent may vouch for its author in its own record instead.
  • no other fields
author.subjectstringyesThe Network subject the document names.
  • pattern ^usr_[0-9A-HJKMNP-TV-Z]{26}$
author.namestring
  • maxLength 80
integrityobjectyes
  • no other fields
integrity.algconstyesHow the document was checked: sha256 over the canonical JSON.
  • = "sha256"
integrity.hashstringyesThe hex sha256 of the canonical JSON. It shows the file was not edited; it proves nothing about who wrote it.
  • pattern ^[0-9a-f]{64}$
created_atstringWhen the document was written. Not part of the hash.
  • format date-time

Examples

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

Valid: minimal
{
  "voice": "actor.voice@1",
  "name": "House voice",
  "instructions": "You are the house voice of this household. Speak plainly, be brief, and never guess.",
  "level": "ask",
  "created_at": "2026-11-07T10:00:00.000Z",
  "integrity": {
    "alg": "sha256",
    "hash": "b2c36f80aa7566925d6a9c6707416a0df9604497fb70c6649852afd7c40ceb5f"
  }
}
Valid: researcher
{
  "voice": "actor.voice@1",
  "name": "Researcher",
  "bio": "Reads carefully and dates every claim.",
  "face": "preset:researcher",
  "instructions": "Research carefully. Prefer primary sources, date every claim, and say plainly when the evidence does not settle a question.",
  "rules": [
    "Never invent a source.",
    "Say what you could not confirm."
  ],
  "level": "ask",
  "model": {
    "engine": "runtime",
    "model": "smart"
  },
  "apps": [
    "connect.email"
  ],
  "author": {
    "subject": "usr_01M4C49CW34NGX7TR2TNRVFWNY",
    "name": "Ada"
  },
  "created_at": "2026-11-07T09:31:00.000Z",
  "integrity": {
    "alg": "sha256",
    "hash": "c2cf6349a416047e26715f8def1396c42e60698bb9869abd710727c2798fea4b"
  }
}
Rejected: bad-level
{
  "voice": "actor.voice@1",
  "name": "Researcher",
  "instructions": "Research carefully.",
  "level": "everything",
  "author": {
    "subject": "usr_01M4C49CW34NGX7TR2TNRVFWNY"
  },
  "integrity": {
    "alg": "sha256",
    "hash": "0000000000000000000000000000000000000000000000000000000000000000"
  }
}
Rejected: memory
{
  "voice": "actor.voice@1",
  "name": "Researcher",
  "instructions": "Research carefully.",
  "level": "ask",
  "author": {
    "subject": "usr_01M4C49CW34NGX7TR2TNRVFWNY"
  },
  "integrity": {
    "alg": "sha256",
    "hash": "0000000000000000000000000000000000000000000000000000000000000000"
  },
  "memory": "mems_01M4C49CW7R8S9T0A1B2C3D4E5"
}
Rejected: tokens
{
  "voice": "actor.voice@1",
  "name": "Researcher",
  "instructions": "Research carefully.",
  "level": "ask",
  "author": {
    "subject": "usr_01M4C49CW34NGX7TR2TNRVFWNY"
  },
  "integrity": {
    "alg": "sha256",
    "hash": "0000000000000000000000000000000000000000000000000000000000000000"
  },
  "tokens": {
    "connect": {
      "email": "sk-live-1234567890"
    }
  }
}

Validate

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