openvibers/openvibe.contracts Commits

Dock v2: the run row's words, the subject and the synced choice (#380)

OP OpenVibers committed 4 days ago · 431aef0a33 · 76 files, +1953 −114

* Dock v2: the run row's words, the subject and the synced choice

The Dock's Agents list showed 34 identical rows and raw provider JSON. The action
feed now carries the skill, the subject (kind, title, url), the model, the maker, the
cost, the duration and the live step of every run, and a failed run carries
ai.run-error@1: a code, words, the next step and the action, never a raw response.

The Dock's synced state gains the Vibe conversation a person chose and the Agents
filter they left it on, so both follow them across sites. Chat lists a person's Vibe
conversations, and Actor starts a catalogue skill as an ordinary task.

* Dock v2: the routes behind the run rows

The Dock starts a catalogue skill on Actor and retries a run through the service
that owns it, and it reads a person's Vibe conversations from Chat. Each route now
names the capability that performs it: actor.skill.run for POST /api/v1/runs,
network.skill.run for the proxy the Dock calls, and the retry action on the route
that already approved, declined and cancelled.

* Merge origin/main into the Dock v2 contracts

The 4.165.0 to 0.361.0 releases took the version numbers; this branch is 0.362.0.

* 0.365.0: on top of main (Dock v2: action-item words, ai.run-error@1, skill runs and V)

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 39c12e61..f4b92df5 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -1,5 +1,9 @@
# Changelog
++## 0.365.0 — 2026-11-09
++
++- Dock v2: action-item words, ai.run-error@1, skill runs and Vibe conversations
++
## 0.364.0 — 2026-11-09
- The Feed of everything: community.feed-item@1
ddiff --git a/contracts/actor/skill-run-request.v1.json b/contracts/actor/skill-run-request.v1.json
nnew file mode 100644
iindex 00000000..117d5dcb
---- /dev/null
++++ b/contracts/actor/skill-run-request.v1.json
@@@ -0,0 +1,38 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/actor/skill-run-request.v1.json",
++ "title": "ActorSkillRunRequest",
++ "description": "actor.skill-run-request@1: POST /api/v1/runs starts a public prompt skill as this person, using normal task approvals and budget.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "skill"
++ ],
++ "properties": {
++ "skill": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 80
++ },
++ "input": {
++ "type": "object",
++ "additionalProperties": true,
++ "maxProperties": 30
++ },
++ "choice": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "mode": {
++ "enum": [
++ "cheapest",
++ "balanced",
++ "best",
++ "fastest",
++ "private"
++ ]
++ }
++ }
++ }
++ }
++}
ddiff --git a/contracts/actor/skill-run-result.v1.json b/contracts/actor/skill-run-result.v1.json
nnew file mode 100644
iindex 00000000..3c3737f6
---- /dev/null
++++ b/contracts/actor/skill-run-result.v1.json
@@@ -0,0 +1,34 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/actor/skill-run-result.v1.json",
++ "title": "ActorSkillRunResult",
++ "description": "actor.skill-run-result@1: a catalogue run is an ordinary Actor task, with its skill and subject labelled.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "run"
++ ],
++ "properties": {
++ "run": {
++ "type": "object",
++ "required": [
++ "id",
++ "skill",
++ "subject"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^tsk_"
++ },
++ "skill": {
++ "type": "string"
++ },
++ "subject": {
++ "type": "string"
++ }
++ }
++ }
++ }
++}
ddiff --git a/contracts/ai/run-error.v1.json b/contracts/ai/run-error.v1.json
nnew file mode 100644
iindex 00000000..dcc9d73a
---- /dev/null
++++ b/contracts/ai/run-error.v1.json
@@@ -0,0 +1,44 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/ai/run-error.v1.json",
++ "title": "AiRunError",
++ "description": "ai.run-error@1: safe, actionable words for an AI or Actor run. Raw provider responses are never display text. The code map is shared across products.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "code",
++ "words",
++ "next",
++ "action"
++ ],
++ "properties": {
++ "code": {
++ "type": "string",
++ "maxLength": 80
++ },
++ "words": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "next": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "action": {
++ "enum": [
++ "pick_model",
++ "add_key",
++ "retry",
++ "retry_later",
++ "open"
++ ]
++ },
++ "retry_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "date-time"
++ }
++ }
++}
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex a718373e..101f2b15 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -1571,6 +1571,15 @@
"status": "active",
"adr": "ADR-015"
},
++ {
++ "id": "ai.run-error",
++ "version": "1.0.0",
++ "owner": "ai",
++ "schema": "ai/run-error.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
{
"id": "ai.call.recorded",
"version": "1.0.0",
@@@ -5702,6 +5711,15 @@
"compatibility": "backward",
"status": "active"
},
++ {
++ "id": "chat.vibe-conversations-result",
++ "version": "1.0.0",
++ "owner": "chat",
++ "schema": "chat/vibe-conversations-result.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
{
"id": "chat.vibe-deliver-request",
"version": "1.0.0",
@@@ -8701,7 +8719,7 @@
},
{
"id": "common.action-item",
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "contracts",
"schema": "common/action-item.v1.json",
"visibility": "public",
@@@ -8710,7 +8728,7 @@
},
{
"id": "common.action-list-result",
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "contracts",
"schema": "common/action-list-result.v1.json",
"visibility": "public",
@@@ -8719,7 +8737,7 @@
},
{
"id": "network.me-actions-result",
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "network",
"schema": "network/me-actions-result.v1.json",
"visibility": "public",
@@@ -8728,7 +8746,7 @@
},
{
"id": "network.dock-state",
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "network",
"schema": "network/dock-state.v1.json",
"visibility": "public",
@@@ -10279,6 +10297,24 @@
"status": "active",
"adr": "ADR-058"
},
++ {
++ "id": "actor.skill-run-request",
++ "version": "1.0.0",
++ "owner": "actor",
++ "schema": "actor/skill-run-request.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "actor.skill-run-result",
++ "version": "1.0.0",
++ "owner": "actor",
++ "schema": "actor/skill-run-result.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
{
"id": "actor.skill",
"version": "2.1.0",
ddiff --git a/contracts/chat/vibe-conversations-result.v1.json b/contracts/chat/vibe-conversations-result.v1.json
nnew file mode 100644
iindex 00000000..85961f33
---- /dev/null
++++ b/contracts/chat/vibe-conversations-result.v1.json
@@@ -0,0 +1,72 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/chat/vibe-conversations-result.v1.json",
++ "title": "ChatVibeConversationsResult",
++ "description": "chat.vibe-conversations-result@1: GET /api/vibe/conversations for a person, newest first. The last line and origin site are omitted when none is known.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "conversations",
++ "count"
++ ],
++ "properties": {
++ "count": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "conversations": {
++ "type": "array",
++ "maxItems": 100,
++ "items": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "slug",
++ "name",
++ "last_message_at",
++ "created_at",
++ "last_line",
++ "last_answer_at",
++ "site"
++ ],
++ "properties": {
++ "slug": {
++ "type": "string"
++ },
++ "name": {
++ "type": "string"
++ },
++ "last_message_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "created_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "last_line": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 160
++ },
++ "last_answer_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "date-time"
++ },
++ "site": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ }
++ }
++ }
++ }
++ }
++}
ddiff --git a/contracts/common/action-item.v1.json b/contracts/common/action-item.v1.json
iindex da12890d..9352d2e0 100644
---- a/contracts/common/action-item.v1.json
++++ b/contracts/common/action-item.v1.json
@@@ -143,6 +143,85 @@
"retry"
]
}
++ },
++ "skill": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120,
++ "description": "Catalogue skill key, when this run came from a skill."
++ },
++ "subject": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title",
++ "url"
++ ],
++ "properties": {
++ "kind": {
++ "type": "string",
++ "maxLength": 60
++ },
++ "title": {
++ "type": "string",
++ "maxLength": 160
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri",
++ "pattern": "^https://"
++ }
++ },
++ "description": "The content this run is about, with its canonical page when known."
++ },
++ "model": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ },
++ "maker": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 80
++ },
++ "duration_ms": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "run_error": {
++ "oneOf": [
++ {
++ "type": "null"
++ },
++ {
++ "$ref": "../ai/run-error.v1.json"
++ }
++ ],
++ "description": "Safe error words and the next useful action. Never a raw provider response."
++ },
++ "step": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 240,
++ "description": "The latest live step in plain words."
}
}
}
ddiff --git a/contracts/network/dock-state.v1.json b/contracts/network/dock-state.v1.json
iindex 318e893a..97887869 100644
---- a/contracts/network/dock-state.v1.json
++++ b/contracts/network/dock-state.v1.json
@@@ -35,6 +35,17 @@
"maxLength": 80,
"description": "The conversation the Chats tab has open, or null."
},
++ "vibe": {
++ "description": "The Vibe conversation selected across sites, and when the person last opened it. An older selection opens the list instead.",
++ "oneOf": [
++ { "type": "null" },
++ { "type": "object", "additionalProperties": false, "required": ["slug", "at"], "properties": {
++ "slug": { "type": "string", "minLength": 1, "maxLength": 80, "pattern": "^[A-Za-z0-9_-]+$" },
++ "at": { "type": "string", "format": "date-time" }
++ } }
++ ]
++ },
++ "agent_filter": { "enum": ["all", "running", "waiting", "scheduled", "done", "failed"], "description": "The last Agents list filter chosen by this person." },
"timer": {
"description": "The person's timer (plan L48 R2): it counts down in the Dock's pill on every site and rings at its end. Absent or null: none. A focus timer of rounds alternates focus and break by itself.",
"oneOf": [
ddiff --git a/fixtures/actor.skill-run-request/invalid/mode.json b/fixtures/actor.skill-run-request/invalid/mode.json
nnew file mode 100644
iindex 00000000..58fb02e3
---- /dev/null
++++ b/fixtures/actor.skill-run-request/invalid/mode.json
@@@ -0,0 +1 @@
++{"skill":"research-brief","choice":{"mode":"surprise"}}
ddiff --git a/fixtures/actor.skill-run-request/valid/basic.json b/fixtures/actor.skill-run-request/valid/basic.json
nnew file mode 100644
iindex 00000000..bea58d1b
---- /dev/null
++++ b/fixtures/actor.skill-run-request/valid/basic.json
@@@ -0,0 +1 @@
++{"skill":"research-brief","input":{"title":"Trip"},"choice":{"mode":"balanced"}}
ddiff --git a/fixtures/actor.skill-run-result/invalid/id.json b/fixtures/actor.skill-run-result/invalid/id.json
nnew file mode 100644
iindex 00000000..7b7e79ce
---- /dev/null
++++ b/fixtures/actor.skill-run-result/invalid/id.json
@@@ -0,0 +1 @@
++{"run":{"id":"wrong","skill":"research-brief","subject":"Trip"}}
ddiff --git a/fixtures/actor.skill-run-result/valid/basic.json b/fixtures/actor.skill-run-result/valid/basic.json
nnew file mode 100644
iindex 00000000..9665c0f4
---- /dev/null
++++ b/fixtures/actor.skill-run-result/valid/basic.json
@@@ -0,0 +1 @@
++{"run":{"id":"tsk_example","skill":"research-brief","subject":"Trip"}}
ddiff --git a/fixtures/ai.run-error/invalid/raw.json b/fixtures/ai.run-error/invalid/raw.json
nnew file mode 100644
iindex 00000000..446bc65f
---- /dev/null
++++ b/fixtures/ai.run-error/invalid/raw.json
@@@ -0,0 +1 @@
++{"code":"route.unavailable","words":"Unavailable","next":"Retry","action":"retry","raw":"provider payload"}
ddiff --git a/fixtures/ai.run-error/valid/basic.json b/fixtures/ai.run-error/valid/basic.json
nnew file mode 100644
iindex 00000000..d472e719
---- /dev/null
++++ b/fixtures/ai.run-error/valid/basic.json
@@@ -0,0 +1 @@
++{"code":"route.unavailable","words":"No model could take this task.","next":"Choose a model and retry.","action":"pick_model"}
ddiff --git a/fixtures/chat.vibe-conversations-result/invalid/count.json b/fixtures/chat.vibe-conversations-result/invalid/count.json
nnew file mode 100644
iindex 00000000..9d3767a7
---- /dev/null
++++ b/fixtures/chat.vibe-conversations-result/invalid/count.json
@@@ -0,0 +1 @@
++{"count":-1,"conversations":[]}
ddiff --git a/fixtures/chat.vibe-conversations-result/valid/basic.json b/fixtures/chat.vibe-conversations-result/valid/basic.json
nnew file mode 100644
iindex 00000000..37b801de
---- /dev/null
++++ b/fixtures/chat.vibe-conversations-result/valid/basic.json
@@@ -0,0 +1 @@
++{"count":1,"conversations":[{"slug":"v1","name":"Trip","last_message_at":"2026-11-09T08:00:00Z","created_at":"2026-11-09T07:00:00Z","last_line":"Hello","last_answer_at":null,"site":"openvibe.today"}]}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex fd2e85d6..97a96867 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -16942,6 +16942,55 @@
}
}
},
++ "ai.run-error": {
++ "version": "1.0.0",
++ "owner": "ai",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/ai/run-error.v1.json",
++ "title": "AiRunError",
++ "description": "ai.run-error@1: safe, actionable words for an AI or Actor run. Raw provider responses are never display text. The code map is shared across products.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "code",
++ "words",
++ "next",
++ "action"
++ ],
++ "properties": {
++ "code": {
++ "type": "string",
++ "maxLength": 80
++ },
++ "words": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "next": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "action": {
++ "enum": [
++ "pick_model",
++ "add_key",
++ "retry",
++ "retry_later",
++ "open"
++ ]
++ },
++ "retry_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "date-time"
++ }
++ }
++ }
++ },
"ai.call.recorded": {
"version": "1.0.0",
"owner": "ai",
@@@ -63486,6 +63535,83 @@
}
}
},
++ "chat.vibe-conversations-result": {
++ "version": "1.0.0",
++ "owner": "chat",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/chat/vibe-conversations-result.v1.json",
++ "title": "ChatVibeConversationsResult",
++ "description": "chat.vibe-conversations-result@1: GET /api/vibe/conversations for a person, newest first. The last line and origin site are omitted when none is known.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "conversations",
++ "count"
++ ],
++ "properties": {
++ "count": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "conversations": {
++ "type": "array",
++ "maxItems": 100,
++ "items": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "slug",
++ "name",
++ "last_message_at",
++ "created_at",
++ "last_line",
++ "last_answer_at",
++ "site"
++ ],
++ "properties": {
++ "slug": {
++ "type": "string"
++ },
++ "name": {
++ "type": "string"
++ },
++ "last_message_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "created_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "last_line": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 160
++ },
++ "last_answer_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "date-time"
++ },
++ "site": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"chat.vibe-deliver-request": {
"version": "1.0.0",
"owner": "chat",
@@@ -96354,7 +96480,7 @@
}
},
"common.action-item": {
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "contracts",
"status": "active",
"schema": {
@@@ -96502,12 +96628,91 @@
"retry"
]
}
++ },
++ "skill": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120,
++ "description": "Catalogue skill key, when this run came from a skill."
++ },
++ "subject": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title",
++ "url"
++ ],
++ "properties": {
++ "kind": {
++ "type": "string",
++ "maxLength": 60
++ },
++ "title": {
++ "type": "string",
++ "maxLength": 160
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri",
++ "pattern": "^https://"
++ }
++ },
++ "description": "The content this run is about, with its canonical page when known."
++ },
++ "model": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ },
++ "maker": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 80
++ },
++ "duration_ms": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "run_error": {
++ "oneOf": [
++ {
++ "type": "null"
++ },
++ {
++ "$ref": "../ai/run-error.v1.json"
++ }
++ ],
++ "description": "Safe error words and the next useful action. Never a raw provider response."
++ },
++ "step": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 240,
++ "description": "The latest live step in plain words."
}
}
}
},
"common.action-list-result": {
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "contracts",
"status": "active",
"schema": {
@@@ -96532,7 +96737,7 @@
}
},
"network.me-actions-result": {
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "network",
"status": "active",
"schema": {
@@@ -96658,7 +96863,7 @@
}
},
"network.dock-state": {
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "network",
"status": "active",
"schema": {
@@@ -96731,6 +96936,45 @@
"maxLength": 80,
"description": "The conversation the Chats tab has open, or null."
},
++ "vibe": {
++ "description": "The Vibe conversation selected across sites, and when the person last opened it. An older selection opens the list instead.",
++ "oneOf": [
++ {
++ "type": "null"
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "slug",
++ "at"
++ ],
++ "properties": {
++ "slug": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 80,
++ "pattern": "^[A-Za-z0-9_-]+$"
++ },
++ "at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ }
++ }
++ ]
++ },
++ "agent_filter": {
++ "enum": [
++ "all",
++ "running",
++ "waiting",
++ "scheduled",
++ "done",
++ "failed"
++ ],
++ "description": "The last Agents list filter chosen by this person."
++ },
"timer": {
"description": "The person's timer (plan L48 R2): it counts down in the Dock's pill on every site and rings at its end. Absent or null: none. A focus timer of rounds alternates focus and break by itself.",
"oneOf": [
@@@ -113478,6 +113722,88 @@
}
}
},
++ "actor.skill-run-request": {
++ "version": "1.0.0",
++ "owner": "actor",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/actor/skill-run-request.v1.json",
++ "title": "ActorSkillRunRequest",
++ "description": "actor.skill-run-request@1: POST /api/v1/runs starts a public prompt skill as this person, using normal task approvals and budget.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "skill"
++ ],
++ "properties": {
++ "skill": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 80
++ },
++ "input": {
++ "type": "object",
++ "additionalProperties": true,
++ "maxProperties": 30
++ },
++ "choice": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "mode": {
++ "enum": [
++ "cheapest",
++ "balanced",
++ "best",
++ "fastest",
++ "private"
++ ]
++ }
++ }
++ }
++ }
++ }
++ },
++ "actor.skill-run-result": {
++ "version": "1.0.0",
++ "owner": "actor",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/actor/skill-run-result.v1.json",
++ "title": "ActorSkillRunResult",
++ "description": "actor.skill-run-result@1: a catalogue run is an ordinary Actor task, with its skill and subject labelled.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "run"
++ ],
++ "properties": {
++ "run": {
++ "type": "object",
++ "required": [
++ "id",
++ "skill",
++ "subject"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^tsk_"
++ },
++ "skill": {
++ "type": "string"
++ },
++ "subject": {
++ "type": "string"
++ }
++ }
++ }
++ }
++ }
++ },
"actor.skill@2": {
"version": "2.1.0",
"owner": "actor",
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex c823beea..53a72c81 100644
---- a/generated/openapi/actor.json
++++ b/generated/openapi/actor.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Actor API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
@@@ -2326,6 +2326,62 @@
}
}
},
++ "/api/v1/runs": {
++ "post": {
++ "operationId": "post_api_v1_runs",
++ "summary": "Start a catalogue skill as this person (plan 2026-11-09 §7): POST /api/v1/runs with the skill key, its input and a choice (cheapest, balanced, best, fastest, private).",
++ "description": "**actor.skill.run** (public): Start a catalogue skill as this person (plan 2026-11-09 §7): POST /api/v1/runs with the skill key, its input and a choice (cheapest, balanced, best, fastest, private). The run is an ordinary Actor task with the skill's instructions pinned to it, so editing the catalogue later never changes a task already under way. A skill that needs a sandbox runner cannot start here, and the person still approves what it does.",
++ "tags": [
++ "actor.skill"
++ ],
++ "x-openvibe-capabilities": [
++ "actor.skill.run"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "actor-task",
++ "security": [
++ {
++ "openvibeToken": [
++ "actor.skill.run"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/actor.skill-run-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/actor.skill-run-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"/api/v1/tasks": {
"get": {
"operationId": "get_api_v1_tasks",
@@@ -2734,6 +2790,72 @@
}
}
},
++ "/api/v1/tasks/{id}/retry": {
++ "post": {
++ "operationId": "post_api_v1_tasks_id_retry",
++ "summary": "Give OpenVibe.Actor a task: POST /api/v1/tasks with the task in plain words, a mode (cheapest, balanced, best, fastest, private) and a budget.",
++ "description": "**actor.task.create** (public): Give OpenVibe.Actor a task: POST /api/v1/tasks with the task in plain words, a mode (cheapest, balanced, best, fastest, private) and a budget. Actor picks the agent system for it with openvibe-sdk/placement, runs it, has a second model family check the result, and records the result, the cost to the cent and the explanation on the task (platform.task@1, answered 201 with state queued). POST /api/v1/tasks/:id/cancel stops a task that has not ended. POST /api/v1/tasks/:id/takeover gives the person the Computer the task opened (the agent's input is refused while they drive) and POST /api/v1/tasks/:id/giveback hands it back; both are the task's own person's, built on the same hand-off the agent's hand_to_person tool uses. A person's tasks are theirs; a token that names a project puts the task in that project. Each person has a daily free allowance; a task whose cheapest eligible agent would cost more than its budget fails with actor.budget.exceeded instead of running. A task may register webhooks: Actor POSTs actor.task-webhook@1 to each on the state changes it asked for, signed with a secret minted for the task and returned once, as webhook_secret, in the answer that created it. A canvas (actor.canvas@1, HO9) is also the person's own: POST /api/v1/me/canvases/:id/events with kind \"ask\" posts a button's label as the person's own message (a normal turn, at the agent's level and approvals), and with kind \"check\" flips one checklist item and tells the next turn which item changed.",
++ "tags": [
++ "actor.task"
++ ],
++ "x-openvibe-capabilities": [
++ "actor.task.create"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "actor-task",
++ "security": [
++ {
++ "openvibeToken": [
++ "actor.task.create"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/actor.task-create-request.v1"
++ }
++ }
++ }
++ },
++ "parameters": [
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/platform.task.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"/api/v1/tasks/{id}/still": {
"get": {
"operationId": "get_api_v1_tasks_id_still",
@@@ -4541,6 +4663,74 @@
}
}
},
++ "actor.skill-run-request.v1": {
++ "title": "ActorSkillRunRequest",
++ "description": "actor.skill-run-request@1: POST /api/v1/runs starts a public prompt skill as this person, using normal task approvals and budget.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "skill"
++ ],
++ "properties": {
++ "skill": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 80
++ },
++ "input": {
++ "type": "object",
++ "additionalProperties": true,
++ "maxProperties": 30
++ },
++ "choice": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "mode": {
++ "enum": [
++ "cheapest",
++ "balanced",
++ "best",
++ "fastest",
++ "private"
++ ]
++ }
++ }
++ }
++ }
++ },
++ "actor.skill-run-result.v1": {
++ "title": "ActorSkillRunResult",
++ "description": "actor.skill-run-result@1: a catalogue run is an ordinary Actor task, with its skill and subject labelled.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "run"
++ ],
++ "properties": {
++ "run": {
++ "type": "object",
++ "required": [
++ "id",
++ "skill",
++ "subject"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^tsk_"
++ },
++ "skill": {
++ "type": "string"
++ },
++ "subject": {
++ "type": "string"
++ }
++ }
++ }
++ }
++ },
"actor.task-create-request.v1": {
"title": "ActorTaskCreateRequest",
"description": "actor.task-create-request@1: the body of POST /api/v1/tasks on OpenVibe.Actor (capability actor.task.create), the creation subset of platform.task@1. TASK is the instruction in plain words. MODE is the planner objective (default balanced). BUDGET caps what this task may cost (per_task_usd) and what the caller's tasks may cost in one UTC day (per_day_usd); either may be left out for the person's free-allowance defaults, and a value above the person's tier is refused 422 actor.budget.over_tier, never silently lowered. AGENT pins one agent system by its id from GET /api/v1/agent-systems, the public catalog (routing still checks that it can take the task); AGENT_ID names one of the caller's own agent contacts from GET /api/v1/agents to run this task as (absent: Vibe, their first agent). LEVEL is the thread's approval level; the effective level is the higher of the agent's own level and this one, inherited along the person's own parent chain and never from outside work. IDEMPOTENCY_KEY: a repeat from the same requester within 24 h with an identical body answers the first task (200), with a different body 409 actor.idempotency.conflict. WEBHOOKS (at most 8): each an https URL and the state changes to deliver there (the names of platform.task@1 `state`). Actor signs every delivery with a secret it mints for the task, returned once as `webhook_secret` in the answer that created it (and in an idempotent repeat), and POSTs actor.task-webhook@1 through its egress guard: public addresses only, ports 443 or 8443, no credentials in the URL, never a redirect. A URL that cannot be delivered to is refused 422 actor.webhook.refused. A webhook may instead name a project secret (`secret_ref`, ADR-056): its deliveries are then signed by OpenVibe.Network with that secret, in the same headers, and no webhook_secret is minted when every webhook names one. A secret_ref on a task outside a project is refused 422 actor.webhook.secret_unavailable.",
@@@ -4960,6 +5150,48 @@
}
}
},
++ "ai.run-error.v1": {
++ "title": "AiRunError",
++ "description": "ai.run-error@1: safe, actionable words for an AI or Actor run. Raw provider responses are never display text. The code map is shared across products.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "code",
++ "words",
++ "next",
++ "action"
++ ],
++ "properties": {
++ "code": {
++ "type": "string",
++ "maxLength": 80
++ },
++ "words": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "next": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "action": {
++ "enum": [
++ "pick_model",
++ "add_key",
++ "retry",
++ "retry_later",
++ "open"
++ ]
++ },
++ "retry_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "date-time"
++ }
++ }
++ },
"common.action-item.v1": {
"title": "ActionItem",
"description": "One piece of a person's agent work in the Action Center (plan 2026-10-28 §3.10): an agent task, a coding task, an AI run, or an approval waiting on them. Each authority answers its own items in this shape (common.action-list-result@1); OpenVibe.Network merges them into buckets (network.me-actions-result@1). Text is plain (no markup); a cost is what the person was charged in USD, null when unknown or free; href is a page on the authority's own public site.",
@@@ -5103,6 +5335,85 @@
"retry"
]
}
++ },
++ "skill": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120,
++ "description": "Catalogue skill key, when this run came from a skill."
++ },
++ "subject": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title",
++ "url"
++ ],
++ "properties": {
++ "kind": {
++ "type": "string",
++ "maxLength": 60
++ },
++ "title": {
++ "type": "string",
++ "maxLength": 160
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri",
++ "pattern": "^https://"
++ }
++ },
++ "description": "The content this run is about, with its canonical page when known."
++ },
++ "model": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ },
++ "maker": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 80
++ },
++ "duration_ms": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "run_error": {
++ "oneOf": [
++ {
++ "type": "null"
++ },
++ {
++ "$ref": "#/components/schemas/ai.run-error.v1"
++ }
++ ],
++ "description": "Safe error words and the next useful action. Never a raw provider response."
++ },
++ "step": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 240,
++ "description": "The latest live step in plain words."
}
}
},
ddiff --git a/generated/openapi/ai.json b/generated/openapi/ai.json
iindex d6abfb07..5d847d66 100644
---- a/generated/openapi/ai.json
++++ b/generated/openapi/ai.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.AI API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
@@@ -7332,6 +7332,48 @@
}
]
},
++ "ai.run-error.v1": {
++ "title": "AiRunError",
++ "description": "ai.run-error@1: safe, actionable words for an AI or Actor run. Raw provider responses are never display text. The code map is shared across products.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "code",
++ "words",
++ "next",
++ "action"
++ ],
++ "properties": {
++ "code": {
++ "type": "string",
++ "maxLength": 80
++ },
++ "words": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "next": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "action": {
++ "enum": [
++ "pick_model",
++ "add_key",
++ "retry",
++ "retry_later",
++ "open"
++ ]
++ },
++ "retry_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "date-time"
++ }
++ }
++ },
"ai.run-read-result.v1": {
"title": "AiRunReadResult",
"description": "ai.run-read-result@1: answers of ai.run.read on OpenVibe.AI (the caller's own runs; usage readers may ask for all). GET /api/v1/runs?status=&workflow=&target=&limit=&before= → { runs }; GET /api/v1/runs/:id → { run, citations, requests } (the request log is metadata only: hashes, tokens, cost, latency, never prompts); GET /api/v1/runs/:id/citations → { citations }. Someone else's run is 404 run.not_found.",
@@@ -8537,6 +8579,85 @@
"retry"
]
}
++ },
++ "skill": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120,
++ "description": "Catalogue skill key, when this run came from a skill."
++ },
++ "subject": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title",
++ "url"
++ ],
++ "properties": {
++ "kind": {
++ "type": "string",
++ "maxLength": 60
++ },
++ "title": {
++ "type": "string",
++ "maxLength": 160
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri",
++ "pattern": "^https://"
++ }
++ },
++ "description": "The content this run is about, with its canonical page when known."
++ },
++ "model": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ },
++ "maker": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 80
++ },
++ "duration_ms": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "run_error": {
++ "oneOf": [
++ {
++ "type": "null"
++ },
++ {
++ "$ref": "#/components/schemas/ai.run-error.v1"
++ }
++ ],
++ "description": "Safe error words and the next useful action. Never a raw provider response."
++ },
++ "step": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 240,
++ "description": "The latest live step in plain words."
}
}
},
ddiff --git a/generated/openapi/bench.json b/generated/openapi/bench.json
iindex f203112a..e2815e05 100644
---- a/generated/openapi/bench.json
++++ b/generated/openapi/bench.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Bench API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/billing.json b/generated/openapi/billing.json
iindex 58dd6b5f..d0a2aad7 100644
---- a/generated/openapi/billing.json
++++ b/generated/openapi/billing.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Billing API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/blog.json b/generated/openapi/blog.json
iindex 94b10a13..ee22ba89 100644
---- a/generated/openapi/blog.json
++++ b/generated/openapi/blog.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Blog API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/bot.json b/generated/openapi/bot.json
iindex 90be6c1e..bb8973a8 100644
---- a/generated/openapi/bot.json
++++ b/generated/openapi/bot.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Bot API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/chat.json b/generated/openapi/chat.json
iindex 1f861f90..b05c859c 100644
---- a/generated/openapi/chat.json
++++ b/generated/openapi/chat.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Chat API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/codes.json b/generated/openapi/codes.json
iindex a4878ae1..d52e4deb 100644
---- a/generated/openapi/codes.json
++++ b/generated/openapi/codes.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Codes API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
@@@ -788,6 +788,48 @@
},
"components": {
"schemas": {
++ "ai.run-error.v1": {
++ "title": "AiRunError",
++ "description": "ai.run-error@1: safe, actionable words for an AI or Actor run. Raw provider responses are never display text. The code map is shared across products.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "code",
++ "words",
++ "next",
++ "action"
++ ],
++ "properties": {
++ "code": {
++ "type": "string",
++ "maxLength": 80
++ },
++ "words": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "next": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "action": {
++ "enum": [
++ "pick_model",
++ "add_key",
++ "retry",
++ "retry_later",
++ "open"
++ ]
++ },
++ "retry_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "date-time"
++ }
++ }
++ },
"codes.task-start-request.v1": {
"title": "CodesTaskStartRequest",
"description": "codes.task-start-request@1: the body of POST /api/v1/tasks on OpenVibe.Codes (capability codes.task.start). A first-party service (OpenVibe.Actor) starts a coding task for a person, named with X-OV-Subject: Codes runs it on that person's own machine through OpenVibe.Run (openvibe.codes/run, plan T16), in the project of their latest task there, so the person has used openvibe.codes/run once before a service can start one for them (else 409 codes.no_project). REPO is an https git URL with no credentials; REF a branch or tag to start from (default: the repository's default branch). PROMPT is the task. AGENT names one of Codes' agents (GET /harnesses), absent for Codes' router to pick. PERMISSION: review (read-only: research, audits, reviews; nothing is changed), edit (default; the agents edit files) or full (they may also run commands: tests, installs). PUSH asks for the change on a new branch (GitHub, with the machine's GITHUB_TOKEN; never the branch it started from), PULL_REQUEST also opens a pull request. IDEMPOTENCY_KEY: a repeat for the same person with the same key answers the first task (200, created false).",
@@@ -1596,6 +1638,85 @@
"retry"
]
}
++ },
++ "skill": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120,
++ "description": "Catalogue skill key, when this run came from a skill."
++ },
++ "subject": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title",
++ "url"
++ ],
++ "properties": {
++ "kind": {
++ "type": "string",
++ "maxLength": 60
++ },
++ "title": {
++ "type": "string",
++ "maxLength": 160
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri",
++ "pattern": "^https://"
++ }
++ },
++ "description": "The content this run is about, with its canonical page when known."
++ },
++ "model": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ },
++ "maker": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 80
++ },
++ "duration_ms": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "run_error": {
++ "oneOf": [
++ {
++ "type": "null"
++ },
++ {
++ "$ref": "#/components/schemas/ai.run-error.v1"
++ }
++ ],
++ "description": "Safe error words and the next useful action. Never a raw provider response."
++ },
++ "step": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 240,
++ "description": "The latest live step in plain words."
}
}
},
ddiff --git a/generated/openapi/community.json b/generated/openapi/community.json
iindex 28f258b2..20275706 100644
---- a/generated/openapi/community.json
++++ b/generated/openapi/community.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Community API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/connect.json b/generated/openapi/connect.json
iindex 3df0ebc1..141aa015 100644
---- a/generated/openapi/connect.json
++++ b/generated/openapi/connect.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe Connect API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe Connect as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe Connect as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/coupons.json b/generated/openapi/coupons.json
iindex da644a4d..8eb8a018 100644
---- a/generated/openapi/coupons.json
++++ b/generated/openapi/coupons.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Coupons API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/deals.json b/generated/openapi/deals.json
iindex b0e20b68..7e2c81d1 100644
---- a/generated/openapi/deals.json
++++ b/generated/openapi/deals.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Deals API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/design.json b/generated/openapi/design.json
iindex fd7538b1..78abf108 100644
---- a/generated/openapi/design.json
++++ b/generated/openapi/design.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Design API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Design as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Design as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/domains.json b/generated/openapi/domains.json
iindex 8565b8d9..952605a1 100644
---- a/generated/openapi/domains.json
++++ b/generated/openapi/domains.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Domains API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
@@@ -676,6 +676,48 @@
},
"components": {
"schemas": {
++ "ai.run-error.v1": {
++ "title": "AiRunError",
++ "description": "ai.run-error@1: safe, actionable words for an AI or Actor run. Raw provider responses are never display text. The code map is shared across products.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "code",
++ "words",
++ "next",
++ "action"
++ ],
++ "properties": {
++ "code": {
++ "type": "string",
++ "maxLength": 80
++ },
++ "words": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "next": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "action": {
++ "enum": [
++ "pick_model",
++ "add_key",
++ "retry",
++ "retry_later",
++ "open"
++ ]
++ },
++ "retry_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "date-time"
++ }
++ }
++ },
"common.action-item.v1": {
"title": "ActionItem",
"description": "One piece of a person's agent work in the Action Center (plan 2026-10-28 §3.10): an agent task, a coding task, an AI run, or an approval waiting on them. Each authority answers its own items in this shape (common.action-list-result@1); OpenVibe.Network merges them into buckets (network.me-actions-result@1). Text is plain (no markup); a cost is what the person was charged in USD, null when unknown or free; href is a page on the authority's own public site.",
@@@ -819,6 +861,85 @@
"retry"
]
}
++ },
++ "skill": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120,
++ "description": "Catalogue skill key, when this run came from a skill."
++ },
++ "subject": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title",
++ "url"
++ ],
++ "properties": {
++ "kind": {
++ "type": "string",
++ "maxLength": 60
++ },
++ "title": {
++ "type": "string",
++ "maxLength": 160
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri",
++ "pattern": "^https://"
++ }
++ },
++ "description": "The content this run is about, with its canonical page when known."
++ },
++ "model": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ },
++ "maker": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 80
++ },
++ "duration_ms": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "run_error": {
++ "oneOf": [
++ {
++ "type": "null"
++ },
++ {
++ "$ref": "#/components/schemas/ai.run-error.v1"
++ }
++ ],
++ "description": "Safe error words and the next useful action. Never a raw provider response."
++ },
++ "step": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 240,
++ "description": "The latest live step in plain words."
}
}
},
ddiff --git a/generated/openapi/events.json b/generated/openapi/events.json
iindex 0dc69abc..7cdf275c 100644
---- a/generated/openapi/events.json
++++ b/generated/openapi/events.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Events API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/exchange.json b/generated/openapi/exchange.json
iindex 599307bf..eec9c980 100644
---- a/generated/openapi/exchange.json
++++ b/generated/openapi/exchange.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Exchange API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Exchange as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Exchange as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/food.json b/generated/openapi/food.json
iindex 868e2a48..b1df88b3 100644
---- a/generated/openapi/food.json
++++ b/generated/openapi/food.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Food API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/games.json b/generated/openapi/games.json
iindex 30d01b1a..9d27696f 100644
---- a/generated/openapi/games.json
++++ b/generated/openapi/games.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Games API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/host.json b/generated/openapi/host.json
iindex 5a6f1d77..48b8f1ea 100644
---- a/generated/openapi/host.json
++++ b/generated/openapi/host.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Host API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/index.json b/generated/openapi/index.json
iindex 5184a02d..94472fab 100644
---- a/generated/openapi/index.json
++++ b/generated/openapi/index.json
@@@ -5,8 +5,8 @@
"service": "actor",
"name": "OpenVibe.Actor",
"origin": "https://openvibe.actor",
-- "operations": 55,
-- "capabilities": 17
++ "operations": 57,
++ "capabilities": 18
},
{
"service": "ai",
@@@ -173,8 +173,8 @@
"service": "network",
"name": "OpenVibe.Network",
"origin": "https://openvibe.network",
-- "operations": 67,
-- "capabilities": 38
++ "operations": 68,
++ "capabilities": 39
},
{
"service": "news",
ddiff --git a/generated/openapi/inventory.json b/generated/openapi/inventory.json
iindex 41b3ff59..292db3b2 100644
---- a/generated/openapi/inventory.json
++++ b/generated/openapi/inventory.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Inventory API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/live.json b/generated/openapi/live.json
iindex 1cfb6d35..3910b983 100644
---- a/generated/openapi/live.json
++++ b/generated/openapi/live.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Live API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/mail.json b/generated/openapi/mail.json
iindex 827cd6be..c5f34cc7 100644
---- a/generated/openapi/mail.json
++++ b/generated/openapi/mail.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Mail API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Mail as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Mail as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/media-hub.json b/generated/openapi/media-hub.json
iindex 28406940..da5a4b43 100644
---- a/generated/openapi/media-hub.json
++++ b/generated/openapi/media-hub.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.MediaHub API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/media.json b/generated/openapi/media.json
iindex 10b14603..40febf09 100644
---- a/generated/openapi/media.json
++++ b/generated/openapi/media.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Media API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/network.json b/generated/openapi/network.json
iindex 8607e40b..9894f7b5 100644
---- a/generated/openapi/network.json
++++ b/generated/openapi/network.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Network API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
@@@ -596,7 +596,7 @@
"get": {
"operationId": "get_api_v1_me_actions",
"summary": "The Action Center for the signed-in person (plan 2026-10-28 §3.10): GET /api/v1/me/actions merges Actor, Codes and AI items and Network's own confirmations into running, waiting, scheduled, done and f",
-- "description": "**network.actions.read** (public): The Action Center for the signed-in person (plan 2026-10-28 §3.10): GET /api/v1/me/actions merges Actor, Codes and AI items and Network's own confirmations into running, waiting, scheduled, done and failed (network.me-actions-result@1); POST /api/v1/me/actions/:service/:id/:action approves, declines or cancels through the owning authority. Readable from every OpenVibe site with the person's Network token, like the bell.",
++ "description": "**network.actions.read** (public): The Action Center for the signed-in person (plan 2026-10-28 §3.10): GET /api/v1/me/actions merges Actor, Codes and AI items and Network's own confirmations into running, waiting, scheduled, done and failed (network.me-actions-result@1); POST /api/v1/me/actions/:service/:id/:action approves, declines, cancels or retries through the owning authority. Readable from every OpenVibe site with the person's Network token, like the bell.",
"tags": [
"network.actions"
],
@@@ -642,7 +642,7 @@
"post": {
"operationId": "post_api_v1_me_actions_service_id_action",
"summary": "The Action Center for the signed-in person (plan 2026-10-28 §3.10): GET /api/v1/me/actions merges Actor, Codes and AI items and Network's own confirmations into running, waiting, scheduled, done and f",
-- "description": "**network.actions.read** (public): The Action Center for the signed-in person (plan 2026-10-28 §3.10): GET /api/v1/me/actions merges Actor, Codes and AI items and Network's own confirmations into running, waiting, scheduled, done and failed (network.me-actions-result@1); POST /api/v1/me/actions/:service/:id/:action approves, declines or cancels through the owning authority. Readable from every OpenVibe site with the person's Network token, like the bell.",
++ "description": "**network.actions.read** (public): The Action Center for the signed-in person (plan 2026-10-28 §3.10): GET /api/v1/me/actions merges Actor, Codes and AI items and Network's own confirmations into running, waiting, scheduled, done and failed (network.me-actions-result@1); POST /api/v1/me/actions/:service/:id/:action approves, declines, cancels or retries through the owning authority. Readable from every OpenVibe site with the person's Network token, like the bell.",
"tags": [
"network.actions"
],
@@@ -710,6 +710,72 @@
}
}
},
++ "/api/v1/me/actions/skills/{id}/run": {
++ "post": {
++ "operationId": "post_api_v1_me_actions_skills_id_run",
++ "summary": "Start one of Actor's catalogue skills as the signed-in person (plan 2026-11-09 §7): POST /api/v1/me/actions/skills/:id/run asks Actor to run that skill for them, with the input and the choice.",
++ "description": "**network.skill.run** (public): Start one of Actor's catalogue skills as the signed-in person (plan 2026-11-09 §7): POST /api/v1/me/actions/skills/:id/run asks Actor to run that skill for them, with the input and the choice. Network never runs the skill itself; Actor does, under the person's own approvals and budget.",
++ "tags": [
++ "network.skill"
++ ],
++ "x-openvibe-capabilities": [
++ "network.skill.run"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "standard",
++ "security": [
++ {
++ "openvibeToken": [
++ "network.skill.run"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/actor.skill-run-request.v1"
++ }
++ }
++ }
++ },
++ "parameters": [
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/actor.skill-run-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"/api/v1/me/consent": {
"get": {
"operationId": "get_api_v1_me_consent",
@@@ -4138,6 +4204,116 @@
},
"components": {
"schemas": {
++ "actor.skill-run-request.v1": {
++ "title": "ActorSkillRunRequest",
++ "description": "actor.skill-run-request@1: POST /api/v1/runs starts a public prompt skill as this person, using normal task approvals and budget.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "skill"
++ ],
++ "properties": {
++ "skill": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 80
++ },
++ "input": {
++ "type": "object",
++ "additionalProperties": true,
++ "maxProperties": 30
++ },
++ "choice": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "mode": {
++ "enum": [
++ "cheapest",
++ "balanced",
++ "best",
++ "fastest",
++ "private"
++ ]
++ }
++ }
++ }
++ }
++ },
++ "actor.skill-run-result.v1": {
++ "title": "ActorSkillRunResult",
++ "description": "actor.skill-run-result@1: a catalogue run is an ordinary Actor task, with its skill and subject labelled.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "run"
++ ],
++ "properties": {
++ "run": {
++ "type": "object",
++ "required": [
++ "id",
++ "skill",
++ "subject"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^tsk_"
++ },
++ "skill": {
++ "type": "string"
++ },
++ "subject": {
++ "type": "string"
++ }
++ }
++ }
++ }
++ },
++ "ai.run-error.v1": {
++ "title": "AiRunError",
++ "description": "ai.run-error@1: safe, actionable words for an AI or Actor run. Raw provider responses are never display text. The code map is shared across products.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "code",
++ "words",
++ "next",
++ "action"
++ ],
++ "properties": {
++ "code": {
++ "type": "string",
++ "maxLength": 80
++ },
++ "words": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "next": {
++ "type": "string",
++ "maxLength": 240
++ },
++ "action": {
++ "enum": [
++ "pick_model",
++ "add_key",
++ "retry",
++ "retry_later",
++ "open"
++ ]
++ },
++ "retry_at": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "date-time"
++ }
++ }
++ },
"bot.machine-manage-request.v1": {
"title": "BotMachineManageRequest",
"description": "bot.machine-manage-request@1: what a caller changes on a machine (plan L34, step M2). A rename gives a name; a roles change gives the whole set of roles (network.machine-roles-put@1's shape). The same body is what the network's hub sends to Bot, so both sides speak one shape.",
@@@ -4317,6 +4493,85 @@
"retry"
]
}
++ },
++ "skill": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120,
++ "description": "Catalogue skill key, when this run came from a skill."
++ },
++ "subject": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title",
++ "url"
++ ],
++ "properties": {
++ "kind": {
++ "type": "string",
++ "maxLength": 60
++ },
++ "title": {
++ "type": "string",
++ "maxLength": 160
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri",
++ "pattern": "^https://"
++ }
++ },
++ "description": "The content this run is about, with its canonical page when known."
++ },
++ "model": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ },
++ "maker": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 80
++ },
++ "duration_ms": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "run_error": {
++ "oneOf": [
++ {
++ "type": "null"
++ },
++ {
++ "$ref": "#/components/schemas/ai.run-error.v1"
++ }
++ ],
++ "description": "Safe error words and the next useful action. Never a raw provider response."
++ },
++ "step": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 240,
++ "description": "The latest live step in plain words."
}
}
},
@@@ -6104,6 +6359,45 @@
"maxLength": 80,
"description": "The conversation the Chats tab has open, or null."
},
++ "vibe": {
++ "description": "The Vibe conversation selected across sites, and when the person last opened it. An older selection opens the list instead.",
++ "oneOf": [
++ {
++ "type": "null"
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "slug",
++ "at"
++ ],
++ "properties": {
++ "slug": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 80,
++ "pattern": "^[A-Za-z0-9_-]+$"
++ },
++ "at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ }
++ }
++ ]
++ },
++ "agent_filter": {
++ "enum": [
++ "all",
++ "running",
++ "waiting",
++ "scheduled",
++ "done",
++ "failed"
++ ],
++ "description": "The last Agents list filter chosen by this person."
++ },
"timer": {
"description": "The person's timer (plan L48 R2): it counts down in the Dock's pill on every site and rings at its end. Absent or null: none. A focus timer of rounds alternates focus and break by itself.",
"oneOf": [
ddiff --git a/generated/openapi/news.json b/generated/openapi/news.json
iindex 3aeb2de0..8f3b62f0 100644
---- a/generated/openapi/news.json
++++ b/generated/openapi/news.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.News API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/openre.json b/generated/openapi/openre.json
iindex c3d936c4..75e15759 100644
---- a/generated/openapi/openre.json
++++ b/generated/openapi/openre.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenRestream API",
-- "version": "0.364.0",
-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/play.json b/generated/openapi/play.json
iindex 76030bf7..c4ccb652 100644
---- a/generated/openapi/play.json
++++ b/generated/openapi/play.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Play API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/quest.json b/generated/openapi/quest.json
iindex ffe984e3..a6713699 100644
---- a/generated/openapi/quest.json
++++ b/generated/openapi/quest.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Quest API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/report.json b/generated/openapi/report.json
iindex 8c57f0ed..d5b73a64 100644
---- a/generated/openapi/report.json
++++ b/generated/openapi/report.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Report API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/reviews.json b/generated/openapi/reviews.json
iindex cc9b74d3..25ad7531 100644
---- a/generated/openapi/reviews.json
++++ b/generated/openapi/reviews.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Reviews API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/run.json b/generated/openapi/run.json
iindex 460cb436..a445969d 100644
---- a/generated/openapi/run.json
++++ b/generated/openapi/run.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Run API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/search.json b/generated/openapi/search.json
iindex 7c261d4f..68f648a1 100644
---- a/generated/openapi/search.json
++++ b/generated/openapi/search.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Search API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/services.json b/generated/openapi/services.json
iindex eac56df7..6a99983d 100644
---- a/generated/openapi/services.json
++++ b/generated/openapi/services.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Services API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/sources.json b/generated/openapi/sources.json
iindex 05bb1f51..ded690c8 100644
---- a/generated/openapi/sources.json
++++ b/generated/openapi/sources.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Sources API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/space.json b/generated/openapi/space.json
iindex cab99df5..8cec1639 100644
---- a/generated/openapi/space.json
++++ b/generated/openapi/space.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Space API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/tips.json b/generated/openapi/tips.json
iindex 3b633c49..223139b9 100644
---- a/generated/openapi/tips.json
++++ b/generated/openapi/tips.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tips API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/today.json b/generated/openapi/today.json
iindex 1ddec3d8..eb074a59 100644
---- a/generated/openapi/today.json
++++ b/generated/openapi/today.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Today API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/tools.json b/generated/openapi/tools.json
iindex 5024bbc0..00d251ae 100644
---- a/generated/openapi/tools.json
++++ b/generated/openapi/tools.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tools API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/trade.json b/generated/openapi/trade.json
iindex 97f69e75..b1ee998c 100644
---- a/generated/openapi/trade.json
++++ b/generated/openapi/trade.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Trade API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/vip.json b/generated/openapi/vip.json
iindex 5c09b512..459fd46f 100644
---- a/generated/openapi/vip.json
++++ b/generated/openapi/vip.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.VIP API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/vision.json b/generated/openapi/vision.json
iindex 28669ba3..7b226771 100644
---- a/generated/openapi/vision.json
++++ b/generated/openapi/vision.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Vision API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/watch.json b/generated/openapi/watch.json
iindex 86418016..7ae410e4 100644
---- a/generated/openapi/watch.json
++++ b/generated/openapi/watch.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Watch API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/wiki.json b/generated/openapi/wiki.json
iindex 2efd1736..8bc4ba05 100644
---- a/generated/openapi/wiki.json
++++ b/generated/openapi/wiki.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Wiki API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/work.json b/generated/openapi/work.json
iindex 0b938924..4ec1f134 100644
---- a/generated/openapi/work.json
++++ b/generated/openapi/work.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Work API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/zone.json b/generated/openapi/zone.json
iindex 2df0be88..cfe78837 100644
---- a/generated/openapi/zone.json
++++ b/generated/openapi/zone.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Zone API",
-- "version": "0.364.0",
-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.364.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.365.0",
++ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.365.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/typescript/index.d.ts b/generated/typescript/index.d.ts
iindex 238110cf..db398f54 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -159793,6 +159793,18 @@ export interface AiRun {
} | null;
}
++/** [email protected] (owner: ai) */
++/**
++ * ai.run-error@1: safe, actionable words for an AI or Actor run. Raw provider responses are never display text. The code map is shared across products.
++ */
++export interface AiRunError {
++ code: string;
++ words: string;
++ next: string;
++ action: "pick_model" | "add_key" | "retry" | "retry_later" | "open";
++ retry_at?: string | null;
++}
++
/** [email protected] (owner: ai) */
/**
* ai.call.recorded v1 (plan L40, one AI meter across the network). One AI call, wherever it happened: OpenVibe.AI's own runs, a harness turn in Codes, an Actor task, Vibe, a local model on a person's own machine. who and where: subject (the person, or null when the call is anonymous), attribution (the site or app the call came from, free text such as 'site:design'), surface (the product surface, free text such as 'design.generate' or 'codes.turn'). what ran: system (ai, harness:claude-code, harness:codex, actor, node), provider, model, effort. who paid: paid_by (own_key, openvibe_key, plan, own_machine, free_tier, network_allowance, org_key) and paid_by_detail (for example 'anthropic ...a1b2' for a person's own key, or 'claude-max' for a plan). tokens: input (the UNCACHED input tokens), output, reasoning, cache_read, cache_write (with cache_write_ttl 5m or 1h), images, audio_seconds, video_seconds. money, in USD: list_cost_usd (what the tokens cost at the human-typed list prices), charged_usd (what the payer was actually charged), fee_usd (the network's fee on top), cache_saved_usd (what the cache saved against the plain input price). price_source says where the prices came from ('models', 'pricing', 'flat', or 'no cache price' when no cache price is typed and the cache tokens are priced at the input price), price_date the day the price was checked. how it went: latency_ms, ttft_ms, attempts, outcome. ids: run_id or turn_id, and at. The record carries NO prompt and NO answer text, ever. A ledger (OpenVibe.AI) rolls the records up; a record consumed twice is stored once (idempotent by system and run_id or turn_id). Envelope: subject { type: run, id: <run_id> } or { type: user, id: <subject> }, visibility internal, priority low, actor service:ai.
@@@ -206811,6 +206823,26 @@ export interface ChatVibeAskResult {
code?: string;
}
++/** [email protected] (owner: chat) */
++/**
++ * chat.vibe-conversations-result@1: GET /api/vibe/conversations for a person, newest first. The last line and origin site are omitted when none is known.
++ */
++export interface ChatVibeConversationsResult {
++ count: number;
++ /**
++ * @maxItems 100
++ */
++ conversations: {
++ slug: string;
++ name: string;
++ last_message_at: string;
++ created_at: string;
++ last_line: string | null;
++ last_answer_at: string | null;
++ site: string | null;
++ }[];
++}
++
/** [email protected] (owner: chat) */
/**
* chat.vibe-deliver-request@1: a first-party service puts a result of the person's own work into their Vibe chats (OpenVibe.Actor: each finished run of one of their OpenVibe Agents, when the agent sends its results to Vibe). Chat keeps one chat per source, named after it, and posts the text there as Vibe's message, so each run is a chat they can open and continue. No AI answer is made and nothing counts against their allowance. POST /internal/chat/vibe/deliver, capability chat.vibe.deliver, loopback only.
@@@ -275948,7 +275980,7 @@ export interface BotWatchLinkResult {
share_id?: string;
}
--/** [email protected] (owner: contracts) */
++/** [email protected] (owner: contracts) */
/**
* One piece of a person's agent work in the Action Center (plan 2026-10-28 §3.10): an agent task, a coding task, an AI run, or an approval waiting on them. Each authority answers its own items in this shape (common.action-list-result@1); OpenVibe.Network merges them into buckets (network.me-actions-result@1). Text is plain (no markup); a cost is what the person was charged in USD, null when unknown or free; href is a page on the authority's own public site.
*/
@@@ -276027,9 +276059,32 @@ export interface ActionItem {
"open" | "approve" | "decline" | "cancel" | "retry",
"open" | "approve" | "decline" | "cancel" | "retry"
];
++ /**
++ * Catalogue skill key, when this run came from a skill.
++ */
++ skill?: string | null;
++ /**
++ * The content this run is about, with its canonical page when known.
++ */
++ subject?: {
++ kind: string;
++ title: string;
++ url: string | null;
++ } | null;
++ model?: string | null;
++ maker?: string | null;
++ duration_ms?: number | null;
++ /**
++ * Safe error words and the next useful action. Never a raw provider response.
++ */
++ run_error?: null | AiRunError;
++ /**
++ * The latest live step in plain words.
++ */
++ step?: string | null;
}
--/** [email protected] (owner: contracts) */
++/** [email protected] (owner: contracts) */
/**
* One authority's Action Center items for a person (capabilities actor.actions.read, codes.actions.read, ai.actions.read, domains.actions.read): GET /api/v1/actions?subject=usr_… with the caller's service token. Everything running, waiting or scheduled, then done and failed items from the last 30 days, newest first, at most 50.
*/
@@@ -276040,7 +276095,7 @@ export interface ActionListResult {
items: ActionItem[];
}
--/** [email protected] (owner: network) */
++/** [email protected] (owner: network) */
/**
* The Action Center for the signed-in person (capability network.actions.read, GET /api/v1/me/actions): every authority's items merged into five buckets, newest first in each. sources says how each authority answered; a slow or failing one is left out (partial true), never fails the answer.
*/
@@@ -276066,7 +276121,7 @@ export interface MeActionsResult {
generated_at: string;
}
--/** [email protected] (owner: network) */
++/** [email protected] (owner: network) */
/**
* network.dock-state@1 (the Dock plan 2026-10-30, K-D1): the state of one person's Dock — the little floating surface every OpenVibe site draws. It lives in the Network, not in the browser, because localStorage is per site and the Dock follows the person across every domain. GET /api/v1/me/dock and PUT /api/v1/me/dock on OpenVibe.Network.
*/
@@@ -276094,6 +276149,17 @@ export interface NetworkDockState {
* The conversation the Chats tab has open, or null.
*/
chat: string | null;
++ /**
++ * The Vibe conversation selected across sites, and when the person last opened it. An older selection opens the list instead.
++ */
++ vibe?: null | {
++ slug: string;
++ at: string;
++ };
++ /**
++ * The last Agents list filter chosen by this person.
++ */
++ agent_filter?: "all" | "running" | "waiting" | "scheduled" | "done" | "failed";
/**
* The person's timer (plan L48 R2): it counts down in the Dock's pill on every site and rings at its end. Absent or null: none. A focus timer of rounds alternates focus and break by itself.
*/
@@@ -311139,6 +311205,33 @@ export interface ActorSkill {
};
}
++/** [email protected] (owner: actor) */
++/**
++ * actor.skill-run-request@1: POST /api/v1/runs starts a public prompt skill as this person, using normal task approvals and budget.
++ */
++export interface ActorSkillRunRequest {
++ skill: string;
++ input?: {
++ [k: string]: unknown | undefined;
++ };
++ choice?: {
++ mode?: "cheapest" | "balanced" | "best" | "fastest" | "private";
++ };
++}
++
++/** [email protected] (owner: actor) */
++/**
++ * actor.skill-run-result@1: a catalogue run is an ordinary Actor task, with its skill and subject labelled.
++ */
++export interface ActorSkillRunResult {
++ run: {
++ id: string;
++ skill: string;
++ subject: string;
++ [k: string]: unknown | undefined;
++ };
++}
++
/** [email protected] (owner: actor) */
/**
* actor.skill@2: a skill, the document an agent loads to do one kind of job well (ADR-058, ADR-060). It keeps every field and meaning of actor.skill@1 and adds a way for the skill to bring CODE that runs in a sandbox: RUNS is prompt (as @1, text and instructions only) or sandbox. A sandbox skill carries its code as ordinary TEXT resources (a .js path with media_type text/javascript, at most 64 KiB each, in the integrity hash); TOOLS (1 to 5, only when runs is sandbox) say what an agent may call: a name, a description the agent reads, language javascript (the only one in v1), an ENTRY naming one of the skill's own .js resources, ARGS as a JSON Schema subset (an object whose properties are string, number, integer, boolean or an array of those; enum, maxLength, and pattern at most 200 characters; no $ref and no nested object), NET (deny by default, openvibe-only, public) and LIMITS (wall_ms at most 30000, default 10000; mem_bytes at most 268435456, default 134217728). A sandbox skill's requires.kinds names skill.run; a prompt skill declares no tools. A skill GRANTS NOTHING: requires only declares; the agent's level and approvals decide every step (actor approvals, HO1), and a step of a kind the skill did not declare is a scan finding (actor.skill-listing@2). Code never runs on an OpenVibe server and never sees a secret: it runs as a Run job of class function on a Link that declared the skill runner, with the network its tool declared and the exact bytes the registry scanned. 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 says nothing about who wrote it, so the AUTHOR is a claim; the registry's listing is the only place a publisher is vouched for. The canonical JSON is the document's own fields, in this order: skill, slug, name, description, version, instructions, resources, tools, requires, runs, license, author; an optional field that is absent or empty is left out; resources are [{ path, media_type, text }] in the document's order; tools are [{ name, description, language, entry, args, net, limits }] in the document's order, with an absent net or limits (and each absent limits field) left out and args as the object the document wrote; requires is { kinds, apps, hosts } with empty lists left out; author is { subject } or { subject, name }; the value is the compact JSON of that object (no spaces). CREATED_AT is not hashed.
ddiff --git a/manifests/ai-run-error-codes.v1.json b/manifests/ai-run-error-codes.v1.json
nnew file mode 100644
iindex 00000000..9b86fb6e
---- /dev/null
++++ b/manifests/ai-run-error-codes.v1.json
@@@ -0,0 +1,50 @@
++{
++ "map": "ai.run-error@1",
++ "codes": {
++ "route.unavailable": {
++ "words": "No model could take this task.",
++ "next": "Pick a model or add an AI key, then retry.",
++ "action": "pick_model"
++ },
++ "provider.unavailable": {
++ "words": "The model provider is unavailable.",
++ "next": "Retry when the provider is back.",
++ "action": "retry"
++ },
++ "provider.rate_limited": {
++ "words": "The model provider reached its limit.",
++ "next": "Retry after the limit resets.",
++ "action": "retry_later"
++ },
++ "credentials.unavailable": {
++ "words": "Your AI key is unavailable.",
++ "next": "Add or check your AI key.",
++ "action": "add_key"
++ },
++ "quota.refused": {
++ "words": "Your AI allowance is used up.",
++ "next": "Pick another model or retry when the allowance resets.",
++ "action": "pick_model"
++ },
++ "queue.full": {
++ "words": "AI is busy right now.",
++ "next": "Retry in a moment.",
++ "action": "retry_later"
++ },
++ "run.interrupted": {
++ "words": "This run stopped during a service restart.",
++ "next": "Retry the task.",
++ "action": "retry"
++ },
++ "task.failed": {
++ "words": "This task could not finish.",
++ "next": "Open the task to review it, then retry.",
++ "action": "open"
++ },
++ "unknown": {
++ "words": "This run could not finish.",
++ "next": "Open its details or retry.",
++ "action": "open"
++ }
++ }
++}
ddiff --git a/manifests/capabilities/actor.skill.run.json b/manifests/capabilities/actor.skill.run.json
nnew file mode 100644
iindex 00000000..d5136b65
---- /dev/null
++++ b/manifests/capabilities/actor.skill.run.json
@@@ -0,0 +1,22 @@
++{
++ "id": "actor.skill.run",
++ "version": "1.0",
++ "owner": "actor",
++ "status": "active",
++ "visibility": "public",
++ "description": "Start a catalogue skill as this person (plan 2026-11-09 §7): POST /api/v1/runs with the skill key, its input and a choice (cheapest, balanced, best, fastest, private). The run is an ordinary Actor task with the skill's instructions pinned to it, so editing the catalogue later never changes a task already under way. A skill that needs a sandbox runner cannot start here, and the person still approves what it does.",
++ "inputSchema": "actor.skill-run-request@1",
++ "outputSchema": "actor.skill-run-result@1",
++ "permissions": [
++ "actor:tasks:create"
++ ],
++ "resourceConstraints": [
++ "owner",
++ "project"
++ ],
++ "quotaClass": "actor-task",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/runs"
++ ]
++}
ddiff --git a/manifests/capabilities/actor.task.create.json b/manifests/capabilities/actor.task.create.json
iindex ba9b8e41..dba21e55 100644
---- a/manifests/capabilities/actor.task.create.json
++++ b/manifests/capabilities/actor.task.create.json
@@@ -20,6 +20,7 @@
"implementedBy": [
"POST /api/v1/tasks",
"POST /api/v1/tasks/:id/cancel",
++ "POST /api/v1/tasks/:id/retry",
"POST /api/v1/tasks/:id/takeover",
"POST /api/v1/tasks/:id/giveback",
"POST /api/v1/me/canvases/:id/events"
ddiff --git a/manifests/capabilities/network.actions.read.json b/manifests/capabilities/network.actions.read.json
iindex dde0247c..ed1a52c6 100644
---- a/manifests/capabilities/network.actions.read.json
++++ b/manifests/capabilities/network.actions.read.json
@@@ -4,7 +4,7 @@
"owner": "network",
"status": "active",
"visibility": "public",
-- "description": "The Action Center for the signed-in person (plan 2026-10-28 §3.10): GET /api/v1/me/actions merges Actor, Codes and AI items and Network's own confirmations into running, waiting, scheduled, done and failed (network.me-actions-result@1); POST /api/v1/me/actions/:service/:id/:action approves, declines or cancels through the owning authority. Readable from every OpenVibe site with the person's Network token, like the bell.",
++ "description": "The Action Center for the signed-in person (plan 2026-10-28 §3.10): GET /api/v1/me/actions merges Actor, Codes and AI items and Network's own confirmations into running, waiting, scheduled, done and failed (network.me-actions-result@1); POST /api/v1/me/actions/:service/:id/:action approves, declines, cancels or retries through the owning authority. Readable from every OpenVibe site with the person's Network token, like the bell.",
"permissions": [
"network:read",
"network:write"
ddiff --git a/manifests/capabilities/network.skill.run.json b/manifests/capabilities/network.skill.run.json
nnew file mode 100644
iindex 00000000..328279c3
---- /dev/null
++++ b/manifests/capabilities/network.skill.run.json
@@@ -0,0 +1,21 @@
++{
++ "id": "network.skill.run",
++ "version": "1.0",
++ "owner": "network",
++ "status": "active",
++ "visibility": "public",
++ "description": "Start one of Actor's catalogue skills as the signed-in person (plan 2026-11-09 §7): POST /api/v1/me/actions/skills/:id/run asks Actor to run that skill for them, with the input and the choice. Network never runs the skill itself; Actor does, under the person's own approvals and budget.",
++ "inputSchema": "actor.skill-run-request@1",
++ "outputSchema": "actor.skill-run-result@1",
++ "permissions": [
++ "network:write"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/me/actions/skills/:id/run"
++ ]
++}
ddiff --git a/manifests/services/actor.json b/manifests/services/actor.json
iindex 15becfde..47ae2d9d 100644
---- a/manifests/services/actor.json
++++ b/manifests/services/actor.json
@@@ -17,6 +17,7 @@
},
"capabilities": [
"actor.task.create",
++ "actor.skill.run",
"actor.task.read",
"actor.task.list",
"actor.agent.read",
ddiff --git a/manifests/services/chat.json b/manifests/services/chat.json
iindex 36cba2b3..6cba2480 100644
---- a/manifests/services/chat.json
++++ b/manifests/services/chat.json
@@@ -15,6 +15,7 @@
"apiRoutes": [
{ "method": "GET", "path": "/api/vibe/models" },
{ "method": "GET", "path": "/api/vibe/chat", "responseSchema": "chat.vibe-answer@2" },
++ { "method": "GET", "path": "/api/vibe/conversations", "responseSchema": "chat.vibe-conversations-result@1" },
{ "method": "POST", "path": "/api/vibe/ask" },
{ "method": "POST", "path": "/api/vibe/pick" },
{ "method": "POST", "path": "/api/vibe/prefer" },
ddiff --git a/manifests/services/network.json b/manifests/services/network.json
iindex 08190e47..ac47303e 100644
---- a/manifests/services/network.json
++++ b/manifests/services/network.json
@@@ -84,6 +84,7 @@
"network.staff.read",
"network.status.incident",
"network.actions.read",
++ "network.skill.run",
"network.consent.read",
"network.consent.manage",
"network.machines.read",
ddiff --git a/package-lock.json b/package-lock.json
iindex e898d959..5fd9dcc8 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-contracts",
-- "version": "0.364.0",
++ "version": "0.365.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-contracts",
-- "version": "0.364.0",
++ "version": "0.365.0",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
ddiff --git a/package.json b/package.json
iindex 92c218e0..b922d2d8 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.364.0",
++ "version": "0.365.0",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"types": "generated/typescript/index.d.ts",
ddiff --git a/test/dock-v2-contracts.test.js b/test/dock-v2-contracts.test.js
nnew file mode 100644
iindex 00000000..b47fb216
---- /dev/null
++++ b/test/dock-v2-contracts.test.js
@@@ -0,0 +1,29 @@
++'use strict';
++const assert = require('assert');
++const { validate } = require('..');
++const error = { code: 'route.unavailable', words: 'No model could take this task.', next: 'Pick a model or add an AI key, then retry.', action: 'pick_model' };
++assert.ok(validate('ai.run-error@1', error).valid, 'a safe action error is in the contract');
++assert.ok(!validate('ai.run-error@1', { ...error, raw: '{tried:[...]}' }).valid, 'raw provider payloads have no display field');
++const map = require('../manifests/ai-run-error-codes.v1.json').codes;
++assert.deepStrictEqual(map['route.unavailable'], { words: error.words, next: error.next, action: error.action });
++const item = {
++ service: 'ai', id: 'run_123', kind: 'ai_run', title: 'Draft a post', summary: error.words,
++ bucket: 'failed', state: 'failed', created_at: '2026-11-09T08:00:00.000Z', updated_at: '2026-11-09T08:01:00.000Z',
++ href: 'https://ai.openvibe.services/runs/run_123', actions: ['open'], error: error.words,
++ run_error: error, skill: 'blog.write', subject: { kind: 'post', title: 'Patch notes draft', url: 'https://openvibe.blog/posts/42' },
++ model: 'gpt-5-nano', maker: 'OpenAI', duration_ms: 60000, step: null,
++};
++assert.ok(validate('common.action-item@1', item).valid, 'the action feed carries the run details');
++assert.ok(!validate('common.action-item@1', { ...item, duration_ms: -1 }).valid);
++const state = {
++ open: true, tab: 'vibe', pinned: false, agent: null, chat: null,
++ vibe: { slug: 'v-abc', at: '2026-11-09T08:00:00.000Z' }, agent_filter: 'failed',
++ place: { phone: { corner: 'bottom-right' }, desktop: { corner: 'top-left', width: 420, height: 640 } },
++ updated_at: '2026-11-09T08:00:00.000Z',
++};
++assert.ok(validate('network.dock-state@1', state).valid, 'the recent conversation and Agents filter sync');
++assert.ok(!validate('network.dock-state@1', { ...state, vibe: { slug: '<bad>', at: state.vibe.at } }).valid);
++assert.ok(validate('chat.vibe-conversations-result@1', { count: 1, conversations: [{ slug: 'v-abc', name: 'Patch notes', last_message_at: state.updated_at, created_at: state.updated_at, last_line: 'What changed?', last_answer_at: null, site: 'openvibe.blog' }] }).valid);
++assert.ok(validate('actor.skill-run-request@1', { skill: 'skl_example', input: {}, choice: { mode: 'balanced' } }).valid);
++assert.ok(validate('actor.skill-run-result@1', { run: { id: 'tsk_example', skill: 'blog.write', subject: 'Patch notes' } }).valid);
++console.log('dock v2 contracts: safe errors, action context, synced state, Vibe list and skill runs');