AgentsBlueprint agents.blueprint@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/agents/blueprint.v1.json
agents.blueprint@1 (agent-blueprints.md, 2026-11-12): an agent anyone can read, change, share and run, as one small document of ten parts. FACE is how it looks and sounds (Design), BRAIN which models it may use and what it may pay (Exchange), KNOWS its instructions, skills and knowledge, HANDS the tools it may use (allowed or ask first), PLACES where its work runs (your machines, machines shared with you, OpenVibe computers, a sandbox; Link), MEMORY what it keeps, RULES its approval level, budget and who may ask it, WHEN what starts it, MAKES what it answers with and whether other agents and apps may call it, TEAM a play whose roles are other blueprints. INPUTS are what an installer fills in ({{id}} in KNOWS and WHEN); NEEDS are what an installer must connect first. A blueprint carries no secret and grants nothing: it asks, and an install (agents.install@1) is the installer agreeing. A published version never changes; a new version that asks for more waits for each installer's yes. Money, passwords, deletions, new recipients and posting in a person's name always ask, whatever the level: no field lowers that floor. openvibe-sdk/agents/blueprint validates, fills, compiles and prices one.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
id | string | yes | bp_<ULID>, or a short stock id such as bp_vibe. |
|
version | integer | yes | Counts up from 1. A published version never changes; a draft is the next number. |
|
state | enum | yes | retired: no new installs; existing ones keep running. |
|
name | string | yes |
| |
summary | string | yes | What it does, in a sentence or two. |
|
author | object | yes |
| |
author.type | enum | yes |
| |
author.id | string | yes |
| |
visibility | enum | yes | link: anyone with its address may read and install it. public: also listed on openvibe.design's gallery, every part readable. |
|
forked_from | string | null | The version it was remixed from (bp_…@N); the gallery credits it. |
| |
licence | string | An SPDX id (MIT, CC-BY-4.0, …) for remixes; absent means remixes need the author's yes. |
| |
tags | array of string |
| ||
inputs | array of object | What an installer fills in. Each is used as {{id}} in KNOWS and WHEN. |
| |
inputs[].id | string | yes |
| |
inputs[].type | enum | yes |
| |
inputs[].label | string | yes |
| |
inputs[].help | string |
| ||
inputs[].required | boolean | |||
inputs[].default | string | number | boolean | |||
inputs[].choices | array of string |
| ||
needs | array of object | What an installer must have connected; the install screen checks each and offers the way to connect it. |
| |
needs[].kind | enum | yes |
| |
needs[].what | string | yes | machine: gpu, desk, browser, linux, windows, macos, android; key and plan: a provider (gemini, openai, …); app: a Connect app; robot: a manifest id. |
|
needs[].why | string |
| ||
face | object | How it looks and sounds wherever it shows up: chat, a stream overlay, a robot, a run card. |
| |
face.avatar | string | An https image, a Media id, or a preset such as preset:researcher. |
| |
face.glyph | string | A glyph from the registry, when it has no picture. |
| |
face.hue | integer |
| ||
face.voice | string | null | A TTS voice id, or null for none. |
| |
face.tone | string | How it talks, in words. |
| |
face.greeting | string |
| ||
face.elements | array of string | Design elements it shows (a co-host card on the overlay, a reaction). |
| |
brain | object | Which models it may use. pick auto: the Dispatcher, cheapest that can, escalating only on evidence; size: the cheapest of that size; exact: MODEL only (a person's own pick always wins). |
| |
brain.pick | enum |
| ||
brain.size | enum |
| ||
brain.model | string | An Exchange offer or provider:model id, for pick exact. |
| |
brain.rungs | array of enum | The ladder rungs it may use: the installer's machine, a signed-in plan, their key, the free allowance, credits. |
| |
brain.max_usd_per_m | number | The most it may pay per million tokens on any rung paid per token. |
| |
brain.caps | array of enum |
| ||
brain.depth | enum |
| ||
brain.advisor | object | null | A stronger model it may consult at hard decisions, at most CONSULTS times a run. | ||
brain.decisions | boolean | Yes/no, choose-one and rubric steps go to Decisions (POST /api/v1/decisions) instead of a model writing an answer. | ||
knows | object | yes |
| |
knows.instructions | string | yes | Its instructions, in words. {{id}} is an input. |
|
knows.skills | array of string | Skill ids (Actor's skills, Run's shared skills). |
| |
knows.knowledge | array of object |
| ||
knows.knowledge[].kind | enum | yes |
| |
knows.knowledge[].ref | string | yes |
| |
knows.knowledge[].note | string |
| ||
knows.examples | array of object | Asks with what a good answer does; Try it offers them and Bench grades with them. |
| |
knows.examples[].ask | string | yes |
| |
knows.examples[].good | string | yes |
| |
hands | object |
| ||
hands.tools | array of object | ov:<product>.<tool> a product's tool on the one MCP endpoint; tools:<app> an openvibe.tools app; connect:<app> a Connect app; mcp:https://… the installer's own server; machine:files|shell|desk|browser|screen on its PLACE; robot:<command> a robot's manifest command; harness:<name> a coding harness for code work; agent:bp_…|agt_… another agent as a tool. MODE ask: every use asks first. |
| |
hands.tools[].tool | string | yes |
| |
hands.tools[].mode | enum | yes |
| |
hands.tools[].note | string |
| ||
hands.search | boolean | It may find more tools on the one MCP endpoint by search; each found tool asks first. | ||
places | object |
| ||
places.order | array of enum | Where its work may run, tried in order: none (it only talks and calls tools), own (the installer's machines through Link), shared (machines shared with the installer by a grant), openvibe (OpenVibe computers), sandbox (a throwaway one). A blueprint never names a machine; the install does. |
| |
places.needs | array of enum |
| ||
memory | object |
| ||
memory.scope | enum | yes | person: one memory per installer; thread: per conversation; team: shared by a TEAM's roles. |
|
memory.remember | string | What is worth keeping, in words. |
| |
memory.keep_days | integer | null |
| ||
rules | object |
| ||
rules.level | enum | actor.agent@1's levels. The floor (money, passwords, deletions, new recipients, posting in a person's name) asks at every level. |
| |
rules.budget | object |
| ||
rules.budget.run_usd | number |
| ||
rules.budget.day_usd | number |
| ||
rules.budget.run_seconds | number |
| ||
rules.budget.run_steps | integer |
| ||
rules.who | object | Who may start it besides its installer (agents.source@1's WHO). Another person's words start a run with a mandate; they are information, never permission. |
| |
rules.who.may | enum | yes |
| |
when | array of object | What starts it, besides being asked directly. KIND is agents.source@1's kinds plus manual and event. |
| |
when[].kind | enum | yes |
| |
when[].rule | string | What counts, in words (a message that names it; a post that reports a bug). |
| |
when[].where | object |
| ||
when[].where.service | string | yes |
| |
when[].where.kind | string |
| ||
when[].where.id | string | An id or an {{input}}. |
| |
when[].event | string | An OpenVibe.Events type, for kind event. |
| |
when[].cron | string | Five fields, for kind schedule. |
| |
when[].tz | string |
| ||
makes | object |
| ||
makes.answer | array of string | What it answers with: text, a card of a registered type (card:clip), a file, a post, a notice, a pull request, a robot action. |
| |
makes.schema | object | null | The exact shape of its answer (a JSON Schema), when it has one. | ||
makes.serve | object |
| ||
makes.serve.a2a | boolean | Listed in Network's A2A directory, so other agents may ask it (behind its RULES.WHO). | ||
makes.serve.mcp | boolean | Offered as a tool on the one MCP endpoint; needs SCHEMA and INPUT. | ||
makes.serve.input | object | null | The JSON Schema of what a caller sends, for mcp. | ||
team | object | null | A play (agents.play@1) whose roles are filled by other blueprints at fixed versions. Absent or null: it works alone. | ||
created_at | string |
| ||
updated_at | string |
| ||
published_at | string | null |
|
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: a-draft-with-a-grader
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PC",
"version": 2,
"state": "draft",
"name": "Patch notes, checked",
"summary": "Writes patch notes from merged pull requests and has another model check them against the diff.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "private",
"forked_from": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PD@4",
"inputs": [
{
"id": "repo",
"type": "repository",
"label": "Repository"
},
{
"id": "style",
"type": "choice",
"label": "Style",
"choices": [
"short",
"full"
],
"default": "short"
}
],
"knows": {
"instructions": "Write {{style}} patch notes for {{repo}} from the pull requests merged since the last release."
},
"team": {
"play": "grader-loop",
"roles": {
"doer": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PE@1",
"grader": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PF@3"
}
},
"when": [
{
"kind": "schedule",
"cron": "0 9 * * 1",
"tz": "Europe/London"
}
],
"makes": {
"answer": [
"post",
"pull-request"
]
}
}Valid: a-robot-driver
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PH",
"version": 1,
"state": "published",
"name": "Desk buddy",
"summary": "Drives a small desk robot: looks at whoever talks, nods, and says hello.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"needs": [
{
"kind": "robot",
"what": "looi",
"why": "It drives a LOOI."
}
],
"brain": {
"pick": "size",
"size": "small",
"caps": [
"vision"
]
},
"knows": {
"instructions": "Turn the head toward whoever is talking. Nod when someone says your name."
},
"hands": {
"tools": [
{
"tool": "robot:head",
"mode": "allow"
},
{
"tool": "robot:drive",
"mode": "ask"
},
{
"tool": "machine:screen",
"mode": "allow"
}
]
},
"places": {
"order": [
"own"
],
"needs": [
"robot"
]
},
"when": [
{
"kind": "machine",
"rule": "Someone starts talking near the robot."
}
],
"makes": {
"answer": [
"robot"
]
},
"published_at": "2026-11-12T21:00:00Z"
}Valid: a-tool-for-other-agents
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PG",
"version": 1,
"state": "published",
"name": "Recipe scaler",
"summary": "Scales a recipe to a number of people and converts the units.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "link",
"brain": {
"pick": "size",
"size": "small",
"caps": [
"json"
]
},
"knows": {
"instructions": "Scale the recipe to the number of people asked for. Metric units unless asked."
},
"rules": {
"level": "full",
"budget": {
"run_usd": 0.01
}
},
"makes": {
"answer": [
"text"
],
"schema": {
"type": "object",
"required": [
"ingredients"
],
"properties": {
"ingredients": {
"type": "array"
}
}
},
"serve": {
"a2a": true,
"mcp": true,
"input": {
"type": "object",
"required": [
"recipe",
"people"
],
"properties": {
"recipe": {
"type": "string"
},
"people": {
"type": "integer"
}
}
}
}
},
"published_at": "2026-11-12T21:00:00Z"
}Valid: clip-finder
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PA",
"version": 3,
"state": "published",
"name": "Clip finder",
"summary": "Watches your stream's chat and speech, and clips the moments people react to.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"forked_from": null,
"licence": "MIT",
"tags": [
"live",
"clips"
],
"inputs": [
{
"id": "channel",
"type": "channel",
"label": "Your channel",
"required": true
}
],
"face": {
"avatar": "preset:scissors",
"hue": 270,
"voice": null,
"tone": "Short and cheerful."
},
"brain": {
"pick": "auto",
"rungs": [
"machine",
"plan",
"key",
"allowance",
"credits"
],
"max_usd_per_m": 1,
"caps": [
"tools"
],
"decisions": true
},
"knows": {
"instructions": "You watch {{channel}}'s stream. A moment is worth a clip when chat reacts within ten seconds of it. Clip twenty to forty seconds around it and name it in five words.",
"examples": [
{
"ask": "Chat floods with LOL after the streamer drops the cup.",
"good": "One clip of the drop, named in five words, no post in chat."
}
]
},
"hands": {
"tools": [
{
"tool": "ov:live.transcript.read",
"mode": "allow"
},
{
"tool": "ov:live.chat.read",
"mode": "allow"
},
{
"tool": "ov:media.clip.create",
"mode": "allow"
},
{
"tool": "ov:live.chat.post",
"mode": "ask"
}
],
"search": false
},
"places": {
"order": [
"none"
]
},
"memory": {
"scope": "person",
"remember": "Which kinds of moments the streamer kept or deleted.",
"keep_days": 30
},
"rules": {
"level": "auto-edits",
"budget": {
"run_usd": 0.05,
"day_usd": 0.5
},
"who": {
"may": "owner"
}
},
"when": [
{
"kind": "event",
"event": "live.stream.started",
"where": {
"service": "live",
"kind": "channel",
"id": "{{channel}}"
}
}
],
"makes": {
"answer": [
"card:clip"
],
"serve": {
"a2a": false,
"mcp": false
}
},
"team": null,
"created_at": "2026-11-10T09:00:00Z",
"updated_at": "2026-11-12T21:00:00Z",
"published_at": "2026-11-12T21:00:00Z"
}Valid: vibe
{
"id": "bp_vibe",
"version": 1,
"state": "published",
"name": "Vibe",
"summary": "The agent every person has: answers, finds things and does small jobs across OpenVibe.",
"author": {
"type": "service",
"id": "actor"
},
"visibility": "public",
"face": {
"glyph": "sparkle",
"hue": 210,
"voice": "polly:Ruth",
"tone": "Warm, plain words, short answers.",
"greeting": "What should we do?"
},
"brain": {
"pick": "auto",
"depth": "balanced",
"advisor": {
"size": "strong",
"consults": 3
}
},
"knows": {
"instructions": "You are Vibe, the person's own agent on OpenVibe. Answer in the shown format. Ask before anything the person did not ask for."
},
"hands": {
"tools": [
{
"tool": "ov:search.query",
"mode": "allow"
},
{
"tool": "harness:auto",
"mode": "ask"
}
],
"search": true
},
"places": {
"order": [
"none",
"own",
"openvibe"
]
},
"memory": {
"scope": "person"
},
"rules": {
"level": "ask",
"who": {
"may": "owner"
}
},
"when": [
{
"kind": "chat",
"rule": "A message that names @Vibe."
},
{
"kind": "composer"
}
],
"makes": {
"answer": [
"text",
"card:link",
"card:table",
"file"
]
},
"published_at": "2026-11-12T00:00:00Z"
}Rejected: a-key-in-the-brain
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PA",
"version": 3,
"state": "published",
"name": "Clip finder",
"summary": "Watches your stream's chat and speech, and clips the moments people react to.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"forked_from": null,
"licence": "MIT",
"tags": [
"live",
"clips"
],
"inputs": [
{
"id": "channel",
"type": "channel",
"label": "Your channel",
"required": true
}
],
"face": {
"avatar": "preset:scissors",
"hue": 270,
"voice": null,
"tone": "Short and cheerful."
},
"brain": {
"pick": "auto",
"rungs": [
"machine",
"plan",
"key",
"allowance",
"credits"
],
"max_usd_per_m": 1,
"caps": [
"tools"
],
"decisions": true,
"api_key": "sk-not-a-real-key"
},
"knows": {
"instructions": "You watch {{channel}}'s stream. A moment is worth a clip when chat reacts within ten seconds of it. Clip twenty to forty seconds around it and name it in five words.",
"examples": [
{
"ask": "Chat floods with LOL after the streamer drops the cup.",
"good": "One clip of the drop, named in five words, no post in chat."
}
]
},
"hands": {
"tools": [
{
"tool": "ov:live.transcript.read",
"mode": "allow"
},
{
"tool": "ov:live.chat.read",
"mode": "allow"
},
{
"tool": "ov:media.clip.create",
"mode": "allow"
},
{
"tool": "ov:live.chat.post",
"mode": "ask"
}
],
"search": false
},
"places": {
"order": [
"none"
]
},
"memory": {
"scope": "person",
"remember": "Which kinds of moments the streamer kept or deleted.",
"keep_days": 30
},
"rules": {
"level": "auto-edits",
"budget": {
"run_usd": 0.05,
"day_usd": 0.5
},
"who": {
"may": "owner"
}
},
"when": [
{
"kind": "event",
"event": "live.stream.started",
"where": {
"service": "live",
"kind": "channel",
"id": "{{channel}}"
}
}
],
"makes": {
"answer": [
"card:clip"
],
"serve": {
"a2a": false,
"mcp": false
}
},
"team": null,
"created_at": "2026-11-10T09:00:00Z",
"updated_at": "2026-11-12T21:00:00Z",
"published_at": "2026-11-12T21:00:00Z"
}Rejected: a-machine-by-name
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PA",
"version": 3,
"state": "published",
"name": "Clip finder",
"summary": "Watches your stream's chat and speech, and clips the moments people react to.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"forked_from": null,
"licence": "MIT",
"tags": [
"live",
"clips"
],
"inputs": [
{
"id": "channel",
"type": "channel",
"label": "Your channel",
"required": true
}
],
"face": {
"avatar": "preset:scissors",
"hue": 270,
"voice": null,
"tone": "Short and cheerful."
},
"brain": {
"pick": "auto",
"rungs": [
"machine",
"plan",
"key",
"allowance",
"credits"
],
"max_usd_per_m": 1,
"caps": [
"tools"
],
"decisions": true
},
"knows": {
"instructions": "You watch {{channel}}'s stream. A moment is worth a clip when chat reacts within ten seconds of it. Clip twenty to forty seconds around it and name it in five words.",
"examples": [
{
"ask": "Chat floods with LOL after the streamer drops the cup.",
"good": "One clip of the drop, named in five words, no post in chat."
}
]
},
"hands": {
"tools": [
{
"tool": "ov:live.transcript.read",
"mode": "allow"
},
{
"tool": "ov:live.chat.read",
"mode": "allow"
},
{
"tool": "ov:media.clip.create",
"mode": "allow"
},
{
"tool": "ov:live.chat.post",
"mode": "ask"
}
],
"search": false
},
"places": {
"order": [
"desk-pc"
]
},
"memory": {
"scope": "person",
"remember": "Which kinds of moments the streamer kept or deleted.",
"keep_days": 30
},
"rules": {
"level": "auto-edits",
"budget": {
"run_usd": 0.05,
"day_usd": 0.5
},
"who": {
"may": "owner"
}
},
"when": [
{
"kind": "event",
"event": "live.stream.started",
"where": {
"service": "live",
"kind": "channel",
"id": "{{channel}}"
}
}
],
"makes": {
"answer": [
"card:clip"
],
"serve": {
"a2a": false,
"mcp": false
}
},
"team": null,
"created_at": "2026-11-10T09:00:00Z",
"updated_at": "2026-11-12T21:00:00Z",
"published_at": "2026-11-12T21:00:00Z"
}Rejected: a-schedule-without-a-time
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PA",
"version": 3,
"state": "published",
"name": "Clip finder",
"summary": "Watches your stream's chat and speech, and clips the moments people react to.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"forked_from": null,
"licence": "MIT",
"tags": [
"live",
"clips"
],
"inputs": [
{
"id": "channel",
"type": "channel",
"label": "Your channel",
"required": true
}
],
"face": {
"avatar": "preset:scissors",
"hue": 270,
"voice": null,
"tone": "Short and cheerful."
},
"brain": {
"pick": "auto",
"rungs": [
"machine",
"plan",
"key",
"allowance",
"credits"
],
"max_usd_per_m": 1,
"caps": [
"tools"
],
"decisions": true
},
"knows": {
"instructions": "You watch {{channel}}'s stream. A moment is worth a clip when chat reacts within ten seconds of it. Clip twenty to forty seconds around it and name it in five words.",
"examples": [
{
"ask": "Chat floods with LOL after the streamer drops the cup.",
"good": "One clip of the drop, named in five words, no post in chat."
}
]
},
"hands": {
"tools": [
{
"tool": "ov:live.transcript.read",
"mode": "allow"
},
{
"tool": "ov:live.chat.read",
"mode": "allow"
},
{
"tool": "ov:media.clip.create",
"mode": "allow"
},
{
"tool": "ov:live.chat.post",
"mode": "ask"
}
],
"search": false
},
"places": {
"order": [
"none"
]
},
"memory": {
"scope": "person",
"remember": "Which kinds of moments the streamer kept or deleted.",
"keep_days": 30
},
"rules": {
"level": "auto-edits",
"budget": {
"run_usd": 0.05,
"day_usd": 0.5
},
"who": {
"may": "owner"
}
},
"when": [
{
"kind": "schedule"
}
],
"makes": {
"answer": [
"card:clip"
],
"serve": {
"a2a": false,
"mcp": false
}
},
"team": null,
"created_at": "2026-11-10T09:00:00Z",
"updated_at": "2026-11-12T21:00:00Z",
"published_at": "2026-11-12T21:00:00Z"
}Rejected: a-team-role-without-a-version
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PA",
"version": 3,
"state": "published",
"name": "Clip finder",
"summary": "Watches your stream's chat and speech, and clips the moments people react to.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"forked_from": null,
"licence": "MIT",
"tags": [
"live",
"clips"
],
"inputs": [
{
"id": "channel",
"type": "channel",
"label": "Your channel",
"required": true
}
],
"face": {
"avatar": "preset:scissors",
"hue": 270,
"voice": null,
"tone": "Short and cheerful."
},
"brain": {
"pick": "auto",
"rungs": [
"machine",
"plan",
"key",
"allowance",
"credits"
],
"max_usd_per_m": 1,
"caps": [
"tools"
],
"decisions": true
},
"knows": {
"instructions": "You watch {{channel}}'s stream. A moment is worth a clip when chat reacts within ten seconds of it. Clip twenty to forty seconds around it and name it in five words.",
"examples": [
{
"ask": "Chat floods with LOL after the streamer drops the cup.",
"good": "One clip of the drop, named in five words, no post in chat."
}
]
},
"hands": {
"tools": [
{
"tool": "ov:live.transcript.read",
"mode": "allow"
},
{
"tool": "ov:live.chat.read",
"mode": "allow"
},
{
"tool": "ov:media.clip.create",
"mode": "allow"
},
{
"tool": "ov:live.chat.post",
"mode": "ask"
}
],
"search": false
},
"places": {
"order": [
"none"
]
},
"memory": {
"scope": "person",
"remember": "Which kinds of moments the streamer kept or deleted.",
"keep_days": 30
},
"rules": {
"level": "auto-edits",
"budget": {
"run_usd": 0.05,
"day_usd": 0.5
},
"who": {
"may": "owner"
}
},
"when": [
{
"kind": "event",
"event": "live.stream.started",
"where": {
"service": "live",
"kind": "channel",
"id": "{{channel}}"
}
}
],
"makes": {
"answer": [
"card:clip"
],
"serve": {
"a2a": false,
"mcp": false
}
},
"team": {
"play": "grader-loop",
"roles": {
"doer": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PE"
}
},
"created_at": "2026-11-10T09:00:00Z",
"updated_at": "2026-11-12T21:00:00Z",
"published_at": "2026-11-12T21:00:00Z"
}Rejected: a-tool-nobody-has
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PA",
"version": 3,
"state": "published",
"name": "Clip finder",
"summary": "Watches your stream's chat and speech, and clips the moments people react to.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"forked_from": null,
"licence": "MIT",
"tags": [
"live",
"clips"
],
"inputs": [
{
"id": "channel",
"type": "channel",
"label": "Your channel",
"required": true
}
],
"face": {
"avatar": "preset:scissors",
"hue": 270,
"voice": null,
"tone": "Short and cheerful."
},
"brain": {
"pick": "auto",
"rungs": [
"machine",
"plan",
"key",
"allowance",
"credits"
],
"max_usd_per_m": 1,
"caps": [
"tools"
],
"decisions": true
},
"knows": {
"instructions": "You watch {{channel}}'s stream. A moment is worth a clip when chat reacts within ten seconds of it. Clip twenty to forty seconds around it and name it in five words.",
"examples": [
{
"ask": "Chat floods with LOL after the streamer drops the cup.",
"good": "One clip of the drop, named in five words, no post in chat."
}
]
},
"hands": {
"tools": [
{
"tool": "ov:live.transcript.read",
"mode": "allow"
},
{
"tool": "ov:live.chat.read",
"mode": "allow"
},
{
"tool": "ov:media.clip.create",
"mode": "allow"
},
{
"tool": "ov:live.chat.post",
"mode": "ask"
},
{
"tool": "shell:rm -rf",
"mode": "allow"
}
],
"search": false
},
"places": {
"order": [
"none"
]
},
"memory": {
"scope": "person",
"remember": "Which kinds of moments the streamer kept or deleted.",
"keep_days": 30
},
"rules": {
"level": "auto-edits",
"budget": {
"run_usd": 0.05,
"day_usd": 0.5
},
"who": {
"may": "owner"
}
},
"when": [
{
"kind": "event",
"event": "live.stream.started",
"where": {
"service": "live",
"kind": "channel",
"id": "{{channel}}"
}
}
],
"makes": {
"answer": [
"card:clip"
],
"serve": {
"a2a": false,
"mcp": false
}
},
"team": null,
"created_at": "2026-11-10T09:00:00Z",
"updated_at": "2026-11-12T21:00:00Z",
"published_at": "2026-11-12T21:00:00Z"
}Rejected: an-exact-pick-without-a-model
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PA",
"version": 3,
"state": "published",
"name": "Clip finder",
"summary": "Watches your stream's chat and speech, and clips the moments people react to.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"forked_from": null,
"licence": "MIT",
"tags": [
"live",
"clips"
],
"inputs": [
{
"id": "channel",
"type": "channel",
"label": "Your channel",
"required": true
}
],
"face": {
"avatar": "preset:scissors",
"hue": 270,
"voice": null,
"tone": "Short and cheerful."
},
"brain": {
"pick": "exact"
},
"knows": {
"instructions": "You watch {{channel}}'s stream. A moment is worth a clip when chat reacts within ten seconds of it. Clip twenty to forty seconds around it and name it in five words.",
"examples": [
{
"ask": "Chat floods with LOL after the streamer drops the cup.",
"good": "One clip of the drop, named in five words, no post in chat."
}
]
},
"hands": {
"tools": [
{
"tool": "ov:live.transcript.read",
"mode": "allow"
},
{
"tool": "ov:live.chat.read",
"mode": "allow"
},
{
"tool": "ov:media.clip.create",
"mode": "allow"
},
{
"tool": "ov:live.chat.post",
"mode": "ask"
}
],
"search": false
},
"places": {
"order": [
"none"
]
},
"memory": {
"scope": "person",
"remember": "Which kinds of moments the streamer kept or deleted.",
"keep_days": 30
},
"rules": {
"level": "auto-edits",
"budget": {
"run_usd": 0.05,
"day_usd": 0.5
},
"who": {
"may": "owner"
}
},
"when": [
{
"kind": "event",
"event": "live.stream.started",
"where": {
"service": "live",
"kind": "channel",
"id": "{{channel}}"
}
}
],
"makes": {
"answer": [
"card:clip"
],
"serve": {
"a2a": false,
"mcp": false
}
},
"team": null,
"created_at": "2026-11-10T09:00:00Z",
"updated_at": "2026-11-12T21:00:00Z",
"published_at": "2026-11-12T21:00:00Z"
}Rejected: full-without-a-budget
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PA",
"version": 3,
"state": "published",
"name": "Clip finder",
"summary": "Watches your stream's chat and speech, and clips the moments people react to.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"forked_from": null,
"licence": "MIT",
"tags": [
"live",
"clips"
],
"inputs": [
{
"id": "channel",
"type": "channel",
"label": "Your channel",
"required": true
}
],
"face": {
"avatar": "preset:scissors",
"hue": 270,
"voice": null,
"tone": "Short and cheerful."
},
"brain": {
"pick": "auto",
"rungs": [
"machine",
"plan",
"key",
"allowance",
"credits"
],
"max_usd_per_m": 1,
"caps": [
"tools"
],
"decisions": true
},
"knows": {
"instructions": "You watch {{channel}}'s stream. A moment is worth a clip when chat reacts within ten seconds of it. Clip twenty to forty seconds around it and name it in five words.",
"examples": [
{
"ask": "Chat floods with LOL after the streamer drops the cup.",
"good": "One clip of the drop, named in five words, no post in chat."
}
]
},
"hands": {
"tools": [
{
"tool": "ov:live.transcript.read",
"mode": "allow"
},
{
"tool": "ov:live.chat.read",
"mode": "allow"
},
{
"tool": "ov:media.clip.create",
"mode": "allow"
},
{
"tool": "ov:live.chat.post",
"mode": "ask"
}
],
"search": false
},
"places": {
"order": [
"none"
]
},
"memory": {
"scope": "person",
"remember": "Which kinds of moments the streamer kept or deleted.",
"keep_days": 30
},
"rules": {
"level": "full"
},
"when": [
{
"kind": "event",
"event": "live.stream.started",
"where": {
"service": "live",
"kind": "channel",
"id": "{{channel}}"
}
}
],
"makes": {
"answer": [
"card:clip"
],
"serve": {
"a2a": false,
"mcp": false
}
},
"team": null,
"created_at": "2026-11-10T09:00:00Z",
"updated_at": "2026-11-12T21:00:00Z",
"published_at": "2026-11-12T21:00:00Z"
}Rejected: no-instructions
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PA",
"version": 3,
"state": "published",
"name": "Clip finder",
"summary": "Watches your stream's chat and speech, and clips the moments people react to.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"forked_from": null,
"licence": "MIT",
"tags": [
"live",
"clips"
],
"inputs": [
{
"id": "channel",
"type": "channel",
"label": "Your channel",
"required": true
}
],
"face": {
"avatar": "preset:scissors",
"hue": 270,
"voice": null,
"tone": "Short and cheerful."
},
"brain": {
"pick": "auto",
"rungs": [
"machine",
"plan",
"key",
"allowance",
"credits"
],
"max_usd_per_m": 1,
"caps": [
"tools"
],
"decisions": true
},
"knows": {
"examples": [
{
"ask": "Chat floods with LOL after the streamer drops the cup.",
"good": "One clip of the drop, named in five words, no post in chat."
}
]
},
"hands": {
"tools": [
{
"tool": "ov:live.transcript.read",
"mode": "allow"
},
{
"tool": "ov:live.chat.read",
"mode": "allow"
},
{
"tool": "ov:media.clip.create",
"mode": "allow"
},
{
"tool": "ov:live.chat.post",
"mode": "ask"
}
],
"search": false
},
"places": {
"order": [
"none"
]
},
"memory": {
"scope": "person",
"remember": "Which kinds of moments the streamer kept or deleted.",
"keep_days": 30
},
"rules": {
"level": "auto-edits",
"budget": {
"run_usd": 0.05,
"day_usd": 0.5
},
"who": {
"may": "owner"
}
},
"when": [
{
"kind": "event",
"event": "live.stream.started",
"where": {
"service": "live",
"kind": "channel",
"id": "{{channel}}"
}
}
],
"makes": {
"answer": [
"card:clip"
],
"serve": {
"a2a": false,
"mcp": false
}
},
"team": null,
"created_at": "2026-11-10T09:00:00Z",
"updated_at": "2026-11-12T21:00:00Z",
"published_at": "2026-11-12T21:00:00Z"
}Rejected: published-without-a-date
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PA",
"version": 3,
"state": "published",
"name": "Clip finder",
"summary": "Watches your stream's chat and speech, and clips the moments people react to.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"forked_from": null,
"licence": "MIT",
"tags": [
"live",
"clips"
],
"inputs": [
{
"id": "channel",
"type": "channel",
"label": "Your channel",
"required": true
}
],
"face": {
"avatar": "preset:scissors",
"hue": 270,
"voice": null,
"tone": "Short and cheerful."
},
"brain": {
"pick": "auto",
"rungs": [
"machine",
"plan",
"key",
"allowance",
"credits"
],
"max_usd_per_m": 1,
"caps": [
"tools"
],
"decisions": true
},
"knows": {
"instructions": "You watch {{channel}}'s stream. A moment is worth a clip when chat reacts within ten seconds of it. Clip twenty to forty seconds around it and name it in five words.",
"examples": [
{
"ask": "Chat floods with LOL after the streamer drops the cup.",
"good": "One clip of the drop, named in five words, no post in chat."
}
]
},
"hands": {
"tools": [
{
"tool": "ov:live.transcript.read",
"mode": "allow"
},
{
"tool": "ov:live.chat.read",
"mode": "allow"
},
{
"tool": "ov:media.clip.create",
"mode": "allow"
},
{
"tool": "ov:live.chat.post",
"mode": "ask"
}
],
"search": false
},
"places": {
"order": [
"none"
]
},
"memory": {
"scope": "person",
"remember": "Which kinds of moments the streamer kept or deleted.",
"keep_days": 30
},
"rules": {
"level": "auto-edits",
"budget": {
"run_usd": 0.05,
"day_usd": 0.5
},
"who": {
"may": "owner"
}
},
"when": [
{
"kind": "event",
"event": "live.stream.started",
"where": {
"service": "live",
"kind": "channel",
"id": "{{channel}}"
}
}
],
"makes": {
"answer": [
"card:clip"
],
"serve": {
"a2a": false,
"mcp": false
}
},
"team": null,
"created_at": "2026-11-10T09:00:00Z",
"updated_at": "2026-11-12T21:00:00Z"
}Rejected: served-as-a-tool-without-a-shape
{
"id": "bp_01JD8C4QJ7Z3K9W2X5V6N1M0PA",
"version": 3,
"state": "published",
"name": "Clip finder",
"summary": "Watches your stream's chat and speech, and clips the moments people react to.",
"author": {
"type": "user",
"id": "usr_01JD8C4QJ7Z3K9W2X5V6N1M0PB"
},
"visibility": "public",
"forked_from": null,
"licence": "MIT",
"tags": [
"live",
"clips"
],
"inputs": [
{
"id": "channel",
"type": "channel",
"label": "Your channel",
"required": true
}
],
"face": {
"avatar": "preset:scissors",
"hue": 270,
"voice": null,
"tone": "Short and cheerful."
},
"brain": {
"pick": "auto",
"rungs": [
"machine",
"plan",
"key",
"allowance",
"credits"
],
"max_usd_per_m": 1,
"caps": [
"tools"
],
"decisions": true
},
"knows": {
"instructions": "You watch {{channel}}'s stream. A moment is worth a clip when chat reacts within ten seconds of it. Clip twenty to forty seconds around it and name it in five words.",
"examples": [
{
"ask": "Chat floods with LOL after the streamer drops the cup.",
"good": "One clip of the drop, named in five words, no post in chat."
}
]
},
"hands": {
"tools": [
{
"tool": "ov:live.transcript.read",
"mode": "allow"
},
{
"tool": "ov:live.chat.read",
"mode": "allow"
},
{
"tool": "ov:media.clip.create",
"mode": "allow"
},
{
"tool": "ov:live.chat.post",
"mode": "ask"
}
],
"search": false
},
"places": {
"order": [
"none"
]
},
"memory": {
"scope": "person",
"remember": "Which kinds of moments the streamer kept or deleted.",
"keep_days": 30
},
"rules": {
"level": "auto-edits",
"budget": {
"run_usd": 0.05,
"day_usd": 0.5
},
"who": {
"may": "owner"
}
},
"when": [
{
"kind": "event",
"event": "live.stream.started",
"where": {
"service": "live",
"kind": "channel",
"id": "{{channel}}"
}
}
],
"makes": {
"answer": [
"card:clip"
],
"serve": {
"mcp": true
}
},
"team": null,
"created_at": "2026-11-10T09:00:00Z",
"updated_at": "2026-11-12T21:00:00Z",
"published_at": "2026-11-12T21:00:00Z"
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('agents.blueprint@1', value); // { valid, errors: [{ path, message }] }