extension.toml
Every extension is a folder with an extension.toml at its root. Core, the node and the apps all
read the same file, and none of them takes one that breaks a rule on this page.
[extension]id = "tickets"name = "Tickets"version = "0.2.0"publisher = "acme"summary = "Open, update and close tickets from a thread."platforms = ["macos-arm64", "linux-x86_64"]
[run]command = ["python", "-m", "tickets"]runtime = "python3.12"
[permissions]network = truesecrets = ["tickets.key"]
[[commands]]kind = "tickets.open"title = "Open a ticket"params = { type = "object", required = ["title"], properties = { title = { type = "string" } } }
[[tools]]name = "tickets_open"command = "tickets.open"description = "Open a ticket in the team's tracker, with this title."returns = "result"Extensions explains how they’re installed and used. The tables below are in the order they usually appear.
[extension]
Section titled “[extension]”Required. What it is.
| Field | Default | Meaning |
|---|---|---|
id |
required | Lowercase letters, digits and _, 2 to 32 characters, starting with a letter. It prefixes every command, tool and event name, and names the repo: pointman-<id>. |
name |
required | What people see, up to 60 characters |
version |
required | A semantic version: 0.2.0, 1.0.0-beta.1 |
publisher |
required | Who publishes it, as an id like acme |
summary |
required | One line, up to 200 characters |
node |
">=0.1,<1" |
The node versions it works with, as a range |
platforms |
[] |
Where it runs: macos-arm64, macos-x86_64, linux-x86_64, linux-arm64, windows-x86_64. Required when it has [run]. |
The process the node starts for it, from the package’s folder. Leave it out for a behaviour, or for a service that runs in core rather than on a node. Commands, tools, events, an MCP server, session hooks and credentials all need it.
| Field | Meaning |
|---|---|
command |
The argv to run, such as ["python", "-m", "tickets"]. For a compiled one, ["bin/<id>", …]. |
runtime |
python3.12 (or another python3.x): the node makes an environment from the package’s lockfile. Or binary, for a compiled extension (below). |
Compiled extensions (runtime = "binary") ship one build per platform. Each release on GitHub
carries one asset per platform in platforms, named <id>-<version>-<platform>.tar.gz, with the
extension’s files at its top, the same extension.toml, and the program at bin/<id>. Core
refuses a release that’s missing one, and each node fetches the build for its own platform. The
node runs bin/<id> from the package’s folder, never a program of that name on your PATH.
[detect]
Section titled “[detect]”Paths whose presence means a machine could use it, per platform: macos, linux, windows. The
apps use them to suggest machines (“Installed on studio; add it for the agents there?”). They’re
suggestions only.
[detect]macos = ["/Applications/Blender.app"]linux = ["/usr/bin/blender"][permissions]
Section titled “[permissions]”What it may touch on the machine. The node holds it to these.
| Field | Default | Meaning |
|---|---|---|
network |
false |
It reaches the network |
gpu |
false |
It uses the GPU |
drives_apps |
[] |
Other apps on the machine it controls, such as DaVinci Resolve |
secrets |
[] |
Vault secrets it may use, by name, or every name under a prefix: rota.* |
folders |
[] |
Folders it reads or writes beyond its own work folder |
[settings]
Section titled “[settings]”A JSON Schema (type = "object") for its settings on each machine. The apps draw it as a form, and
a machine’s own values go in its agent.toml under [extension_settings.<id>]. Every default
must fit its own schema.
[settings]type = "object"
[settings.properties.threshold]type = "integer"minimum = 50maximum = 100default = 90description = "Move new runs off an account once either window is this full (%)"[[commands]]
Section titled “[[commands]]”Work agents can ask a machine for, with run_on_machine or a tool below.
| Field | Default | Meaning |
|---|---|---|
kind |
required | <id>.<verb>, such as tickets.open |
title |
required | What people see, up to 60 characters |
params |
required | A JSON Schema (type = "object") for its parameters, checked before anything runs |
lane |
none | Commands that share a lane run one at a time on a node, such as gpu |
cancellable |
false |
It can be stopped while it runs |
resumable |
false |
It saves checkpoints and carries on after the node restarts |
ready_when |
none | One field of its status that must be true before core sends it work |
outputs |
[] |
What it makes, so the apps know how to show it: image, video, sequence, model, page, audio, document, progress |
[[tools]]
Section titled “[[tools]]”MCP tools for agents, each one making a request of a command. The command’s params are the
tool’s input.
| Field | Default | Meaning |
|---|---|---|
name |
required | <id>_<what it does>, such as tickets_open |
command |
required | One of its own command kinds |
description |
required | What agents are told it does, up to 1,000 characters |
returns |
"accepted" |
accepted: the request’s id at once. result: wait for the result. |
[[events]]
Section titled “[[events]]”Status it reports to core while it runs.
| Field | Meaning |
|---|---|
name |
<id>.<noun>, such as tickets.queue |
description |
What it holds |
[[files]]
Section titled “[[files]]”File types it knows, so the apps can preview them and the Mac can open them.
| Field | Default | Meaning |
|---|---|---|
extensions |
required | Like [".blend"] |
open_with |
none | The app a Mac opens them in |
preview |
none | One of its commands, which makes something every app can show |
An MCP server it brings. The node signs in to it with OAuth and makes the calls, and agents’ sessions
reach it through the node. An agent gets it with /agent.
| Field | Default | Meaning |
|---|---|---|
url |
required | The server’s Streamable HTTP address |
scopes |
[] |
OAuth scopes to ask for. None: what the server says. |
instructions |
none | What sessions are told about it, if the server says nothing, up to 2,000 characters |
[[links]]
Section titled “[[links]]”Links to its service that the apps draw as pills. See Links as pills.
| Field | Meaning |
|---|---|
kind |
The service’s name for it, such as page |
match |
What the link looks like, with {placeholders}: https://pages.example.com/@{owner}/{page} |
show |
What the pill shows, in order: title, repo, number, sha, state, checks, lines |
[behavior]
Section titled “[behavior]”Makes it a behaviour: guidance for agents, with no process, added to the wake prompt of each agent
it’s switched on for. A behaviour has no [run], [[links]] or [[files]]. See
Behaviours.
| Field | Default | Meaning |
|---|---|---|
skill |
"SKILL.md" |
The file with the guidance, frontmatter first |
clients |
all three | The clients it’s written for: claude, codex, gemini |
files |
[] |
Other files or folders in the package that agents read when a task needs them, named in the skill by relative path |
[sessions]
Section titled “[sessions]”Hooks into the agent runs its node starts: it’s asked before each run what to add to the run’s environment, and told how the run ended and how its account’s limits stood. Rota picks each run’s account this way.
| Field | Default | Meaning |
|---|---|---|
clients |
["claude"] |
The clients whose runs it hears about |
env |
required | The environment variables it may set on a run, such as CLAUDE_CODE_OAUTH_TOKEN. The node drops any other. PATH, HOME and the node’s own variables can’t be set. |
[[credentials]]
Section titled “[[credentials]]”Something it needs from a person, such as an API key, drawn by the apps as a form. See Give an extension what it needs.
| Field | Default | Meaning |
|---|---|---|
id |
required | What it is, within the extension |
title |
required | What the apps call it, up to 80 characters |
help |
none | Where to get the value, up to 400 characters |
item |
required | The vault item it’s kept as: <id>.<name>, or <id>.{label} to ask for a label. [permissions] secrets must cover it. |
value |
any text | A regular expression the whole value must match |
placeholder |
none | A hint in the empty field |
needed |
1 |
How many the apps ask for |
sign_in |
false |
true: it signs the account in itself, and the apps offer Sign in |