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

# frame.commands@1 · OpenVibe.Services

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

# FrameCommands `frame.commands@1`

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

- Version: 1.0.0
- Owner: network
- Visibility: public
- Status: active
- Compatibility: backward
- Schema: [`https://openvibe.network/contracts/frame/commands.v1.json`](/docs/contracts/frame.commands.json)

frame.commands@1: what a composer's \`/\` menu offers on one site. GET /api/frame/commands?site=<host>&q= answers this. Every site offers the network's /ask (Vibe answers with sources), /do (Actor plans and runs it), /remind (Today remembers it) and /timer (the Dock's focus timer); a site adds its own from its Frame manifest's site.commands, and a signed-in person's saved composer snippets are theirs. The site's own rows come first because they fit that box, then the network's, then the person's own; a name appears once. q filters by name prefix or hint. \`name\` is the word after the slash (no slash), \`insert\` is the text a pick puts in the box, \`kind\` is where the row came from, and \`needs\_sign\_in\` says the command acts for a person, so a signed-out box may offer it and then sign in. A signed-out answer is public, max-age=60, held a minute; a signed-in one is private, no-store.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `site` | one of | yes | The site the composer asked about; null when the host is not an OpenVibe site (the network's four still answer). |  |
| `commands` | `https://openvibe.network/contracts/frame/commands.v1.json#/$defs/command` | yes |  | - `maxItems 50` |

## Examples

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

 Valid: live

~~~~
{
  "site": {
    "id": "live",
    "name": "Live",
    "host": "openvibe.live"
  },
  "commands": [
    {
      "name": "clip",
      "hint": "Make a clip of the stream",
      "insert": "/clip ",
      "kind": "site",
      "needs_sign_in": true
    },
    {
      "name": "ask",
      "hint": "Ask Vibe: an answer with its sources",
      "insert": "/ask ",
      "kind": "network",
      "needs_sign_in": true
    },
    {
      "name": "do",
      "hint": "Hand it to your agent: Actor plans and runs it",
      "insert": "/do ",
      "kind": "network",
      "needs_sign_in": true
    },
    {
      "name": "remind",
      "hint": "Have Today remind you",
      "insert": "/remind ",
      "kind": "network",
      "needs_sign_in": true
    },
    {
      "name": "timer",
      "hint": "Start a focus timer in the Dock",
      "insert": "/timer ",
      "kind": "network",
      "needs_sign_in": true
    },
    {
      "name": "sig",
      "hint": "Signature",
      "insert": "— Sam",
      "kind": "mine",
      "needs_sign_in": false
    }
  ]
}
~~~~

Valid: no-site

~~~~
{
  "site": null,
  "commands": [
    {
      "name": "ask",
      "hint": "Ask Vibe: an answer with its sources",
      "insert": "/ask ",
      "kind": "network",
      "needs_sign_in": true
    },
    {
      "name": "timer",
      "hint": "Start a focus timer in the Dock",
      "insert": "/timer ",
      "kind": "network",
      "needs_sign_in": true
    }
  ]
}
~~~~

Rejected: leading-slash

~~~~
{
  "site": {
    "id": "live",
    "name": "Live",
    "host": "openvibe.live"
  },
  "commands": [
    {
      "name": "/ask",
      "hint": "Ask Vibe",
      "insert": "/ask ",
      "kind": "network",
      "needs_sign_in": true
    }
  ]
}
~~~~

Rejected: missing-kind

~~~~
{
  "site": null,
  "commands": [
    {
      "name": "ask",
      "hint": "Ask Vibe",
      "insert": "/ask ",
      "needs_sign_in": true
    }
  ]
}
~~~~

## Validate

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