Top-level fields
| Field | Type | Required | Meaning |
|---|---|---|---|
id | string | yes | The plugin’s marketplace identifier. Use the slug while developing. |
slug | string | yes | Stable identifier. [a-z0-9-], at most 64 characters, no leading, trailing or double hyphen. Names the plugin__<slug> tool and the <SLUG>_BIN variable. |
name | string | yes | Display name. Name the service it connects to. |
version | string | yes | Semantic version, such as 0.1.0. |
platforms | map | yes | Platform key to binary. See Platforms. |
description | string | no | One sentence for people and employees. |
author | string | no | Publisher name. |
category | string | no | Helps employees find the plugin. |
triggers | list of strings | no | Words that describe when the plugin applies. Used in search hints. |
entrySkills | list of strings | no | Bundled skills to name first in the plugin’s tool description. |
dependencies | list of {name, version, optional} | no | Other plugins this one runs. version defaults to "*"; optional to false. Their <SLUG>_BIN paths are set on every call. |
auth | object | no | Sign-in and accounts. See Auth. |
capabilities | object | no | configSchema, hooks, commands, routes, providers. |
permissions | object | no | Environment filtering and the timeout ceiling. |
events | list | no | Watchers that feed employee workflows. |
interfaceBindings | map | no | Typed operations the plugin provides. |
channel | object | no | A persistent bridge to a messaging service. |
setup | object | no | A step-by-step setup wizard. |
Nebo validates marketplace installs: the slug rules, a semantic version, at least one platform, a binaryName with no path separators or .., a login command
unless auth.type is env, non-empty event names and commands, and binding
templates that parse. Plugins in the user plugins directory skip validation.
Platforms
Keys are darwin-arm64, darwin-amd64, linux-arm64, linux-amd64, windows-arm64 and windows-amd64. Each entry has
all five fields below. When you publish, the marketplace writes the real hash, size, signature and
download URL, so leave them empty in the file you upload.
"platforms": {
"darwin-arm64": { "binaryName": "notes-sync", "sha256": "", "signature": "", "size": 0, "downloadUrl": "" },
"linux-amd64": { "binaryName": "notes-sync", "sha256": "", "signature": "", "size": 0, "downloadUrl": "" },
"windows-amd64": { "binaryName": "notes-sync.exe", "sha256": "", "signature": "", "size": 0, "downloadUrl": "" }
} | Field | Meaning |
|---|---|
binaryName | The executable’s file name. Add .exe on Windows. |
sha256 | Hash of the binary. Checked at install. |
signature | Signature of the binary. Checked at install when a signing key is available. |
size | Size in bytes. |
downloadUrl | Where Nebo downloads the package. |
Auth
| Field | Meaning |
|---|---|
type | oauth_cli for a browser sign-in run by the plugin; env for credentials entered as values; neboai to receive the owner’s NeboAI token in every auth.env key ending in _TOKEN. |
env | Map of variable name to default value. Also the only credential names Nebo passes to login. |
commands.login | Signs in. Required unless type is env. Runs with the account folder set. |
commands.status | Prints JSON that says whether the account is signed in. |
commands.refresh | Renews a token without interaction. |
commands.logout | Signs out. Only the owner can run it. |
profileDirEnv | Variable that receives a separate credential folder for each employee and account. Without it the plugin holds one shared account. |
label, description | Text on the connect card. |
help | {url, urlLabel, text} shown while connecting. |
publicRedirect | Set true when the provider refuses http://localhost redirects; sign-in then goes through NeboAI’s public redirect. |
Nebo reads the first of authenticated, isAuthenticated, logged_in, loggedIn or token_valid in the status output. A
non-empty token_error, or the value none in credential_source, auth_method, storage or status, means signed out. The status command has 45 seconds.
{"authenticated": true, "account": "finance@example.com"} configSchema
capabilities.configSchema describes the values an owner sets for the plugin. Each value
reaches the binary as an environment variable named by key. For credential keys also
listed in auth.env, the schema labels the fields of the per-employee connect form.
| Field | Type | Default | Meaning |
|---|---|---|---|
key | string | required | Environment variable name. |
label | string | required | Field label. |
description | string | "" | Help text. |
fieldType | string | "string" | Input type, such as string, number, boolean, select or password. |
default | string | none | Pre-filled value. |
required | boolean | false | The plugin is not ready until the value is set. |
secret | boolean | false | The value is masked when read back. |
options | list of strings | none | Choices for select. |
permissions
| Field | Default | Meaning |
|---|---|---|
envAllow | [] | Inherited variables the plugin may see. Empty allows all. |
envDeny | [] | Inherited variables always removed. |
maxTimeoutSeconds | 300 | Upper bound for any call’s timeout. |
network | false | Declares network use. Informational; not enforced. |
events
An event is a long-running watcher. Nebo starts it when an employee's workflow watches it, and
restarts it if it exits. Each line the watcher writes to stdout is one event. The event name is
prefixed with the slug at run time, so note.created becomes notes-sync.note.created.
"events": [
{
"name": "note.created",
"description": "A note was created in the watched notebook.",
"command": "watch --notebook {{notebook}} --format ndjson"
}
] | Field | Meaning |
|---|---|
name | Event name, without the slug. Required. |
command | Arguments that start the watcher. Required. {{key}} is replaced from the employee’s input values. |
description | What causes the event. |
multiplexed | When true, one watcher emits several event types and each line carries an "event" field. |
Workflows subscribe to events with a watch trigger. See Triggers.
interfaceBindings
A binding maps an interface operation to one of your commands. Each binding becomes a typed tool
for employees, named after the operation in lowercase with dots and hyphens as underscores: notes.search becomes notes_search. Bindings are how a plugin satisfies
the capabilities an employee requires; see Capabilities.
"interfaceBindings": {
"notes.search": "notes search --query {query} {tag[]:--tag} {limit?:--limit}",
"invoice.create": "invoices create --amount {amount_cents:cents->dollars}"
} | Placeholder | Expands to |
|---|---|
{field} | The field’s value as one word. The field is not also passed as a flag. |
{field[]:--flag} | One --flag <item> pair for each item in a list field. |
{field?:--flag} | --flag <value> when the field is present; nothing when it is absent. |
{field:cents->dollars} | An integer amount in cents, written as dollars. |
Input fields a template does not name are appended as --field value. List and optional
placeholders must be whole words. An operation that requires approval cannot be reached by calling
the same command through plugin__<slug>.
Hooks, slash commands and routes
"capabilities": {
"hooks": [
{ "hook": "tool.post_execute", "hookType": "filter", "command": "hook redact", "priority": 50, "timeoutMs": 500 }
],
"commands": [
{ "name": "notes", "description": "Show today's notes", "command": "notes today", "slash": true }
],
"routes": [
{ "path": "/callback", "method": "GET", "command": "http callback" }
]
} hooks
A hook runs your command at a point in an employee's turn. Nebo writes a JSON payload to stdin.
An action hook's output is ignored. A filter hook returns {"payload": ..., "handled": false}; "handled": true stops later hooks.
Errors and timeouts keep the previous payload and never block the turn. After three failures in a
row a hook is paused for five minutes.
| Field | Default | Meaning |
|---|---|---|
hook | required | One of tool.pre_execute, tool.post_execute, message.post_receive, session.message_append, steering.generate, agent.turn, agent.should_continue. |
hookType | "action" | action or filter. |
command | required | Arguments for your binary. |
priority | 100 | Lower runs first. |
timeoutMs | 500 | Time limit in milliseconds. |
commands
With "slash": true, typing /name args in chat runs command args directly, without the employee. The output is the reply. The time limit is
30 seconds.
routes
A route answers HTTP requests at /api/v1/plugins/<slug>/api/<path> on the
bot, matched by path and method. The request body goes to stdin and your
stdout is the response. The time limit is 30 seconds.
providers
A provider adds a chat model source. Declare id, displayName, providerType, modelsCommand and chatCommand. Nebo sends a
chat request as JSON on stdin to chatCommand and reads streamed events as
newline-delimited JSON on stdout, for up to 300 seconds. Only chat streaming is used today.
channel
A channel bridges a messaging service. Nebo keeps command running, reads inbound
messages from its stdout and writes replies to its stdin, both as newline-delimited JSON.
| Field | Default | Meaning |
|---|---|---|
command | required | Arguments that start the bridge. |
name, description | "" | Shown in settings. |
restartDelaySecs | 5 | Wait before restarting after a crash. |
shared | false | One bridge for all employees; messages are routed by employee name and replies carry each employee’s identity. |
needsLocalApi | false | Give the bridge the bot’s local API address, a token and the employee id. Off unless you need it. |
setup
A setup wizard walks the owner through steps that a single form cannot cover. Values from form steps fill {{key}} in later generate arguments.
Values from credentials steps are saved as the plugin's environment variables.
"setup": {
"title": "Connect Example Chat",
"steps": [
{ "kind": "form", "title": "Bot name", "fields": [ { "key": "bot_name", "label": "Name", "required": true } ] },
{ "kind": "generate", "title": "App manifest", "command": "manifest", "args": ["--name", "{{bot_name}}"], "outputFormat": "yaml" },
{ "kind": "external", "title": "Create the app", "url": "https://example.com/apps", "urlLabel": "Open admin" },
{ "kind": "credentials", "title": "Paste the token", "fields": [ { "key": "EXAMPLE_CHAT_TOKEN", "label": "Token", "inputType": "password", "required": true } ], "verifyCommand": "auth status" }
]
} | Step kind | Fields |
|---|---|
form | title, description, fields |
generate | title, description, command, args, outputFormat (yaml, json, toml, text), buttonLabel. Shows the command’s output to copy. |
external | title, description, url, urlLabel, instructions |
credentials | title, description, fields, verifyCommand. The step completes when verifyCommand succeeds. |
Fields have key, label, default, placeholder, maxLength, help, inputType (text, textarea, password) and required.