Manifest reference
Edit on GitHubEvery extension has an orrery.toml at its root. It is the contract: what the extension provides, what it asks for, and how it runs. Nothing outside it is available at runtime.
[extension]
api = "orrery-ext/1"
name = "buildgraph"
version = "1.2.0"
runtime = "node"
[provides]
tools = ["impacted", "deps"]
[requires]
read = ["$WORKSPACE/**"]
spawn = ["java"]
net = false
[listing]
homepage = "https://example.com/buildgraph"
image = "docs/card.png"[extension]
| Key | Required | Meaning |
|---|---|---|
api | Yes | The extension API major, "orrery-ext/1". Another major is refused at load. |
name | Yes | The extension id: the namespace of every tool it provides. |
version | Yes | Its own semver version. |
runtime | Yes | native, wasm, node, python, process or none. none starts no process: see Declared extensions. Another name is looked up among the runtimes an extension registered. |
resident | No | true keeps its process running for the whole session, so it is never parked. Default false. [extensions.<id>] resident in config overrides it. Costs one process while the session lasts (Show things: placements). |
An older spelling, with api and runtime at the top level and id instead of name under [extension], is also accepted.
[provides]
Lists of names. Each tool becomes <name>.<tool>.
| Key | Contributes |
|---|---|
tools | Callable tools. |
providers | Model providers. |
agents | Role agents. |
workflows | Multi-step orchestrations. |
interceptors | Hooks around a call. |
lifecycle | Session start and stop handlers. |
graders | Eval verdicts. |
commands | CLI subcommands. |
views | Loop event to surface bindings. |
renderers | Deprecated, and unused: an extension never draws. Still accepted, so no manifest stops loading, and orrery install warns that it is ignored. Use [[provides.elements]] with a fallback, or place a surface with ui.show (Show things: placements). |
skills | Prompt-level capabilities. |
mcp | MCP servers exposed as tools. |
Singletons, one string each. Exactly one extension may hold each; a second claim is a load error:
| Key | Replaces |
|---|---|
memory | The memory backend. |
session | The session store. |
permissions | The permission decision point. |
router | Model routing. |
Tables, for UI packages (see Clients):
[[provides.clients]]:id,label,role(human,machineornamed),entry,draws,fixtures.[[provides.elements]]:id,props(a JSON schema path),fallback,fixture.[[provides.placements]]:id,placement(band,pane.left,pane.rightorfooter),title, and optionallycomponentanddata. The host draws each one in its loading state before the extension is up, and the extension fills it withui.showunder the same id (Show things: placements). Withcomponent, the host fills it itself (below).[[provides.components]]: a structure over the catalog, by name (below).
And one table of tables, [provides.actions.<name>]: what a button in a declared component does (below).
[[provides.components]]
A component is a structure over the catalog orrery/1 and the JSON Schema of its data (Show things: components).
[[provides.components]]
name = "ci"
summary = "The last CI run: its status, what failed, and buttons to explain or rerun it"
file = "ci.json"
schema = { type = "object", properties = { failed = { type = "integer", default = 0 } } }| Key | Required | Meaning |
|---|---|---|
name | Yes | Unique in this manifest. ui.show {component} and a placement's component use it, as <name> or <ext>.<name>. Only this extension may show it: another extension, or the agent, sends an inline structure instead. |
summary | Yes | One line on what it shows, for people and the agent's tool search. |
structure | One of the two | The structure, inline, as a TOML table. |
file | One of the two | A JSON file next to orrery.toml holding the structure. One that fails to read or parse refuses the component, naming the file and the JSON error's line and column. |
schema | No | A JSON Schema object for its data. Its defaults fill missing data, and every update is checked against it. |
Placement component and data
[[provides.placements]]
id = "ci"
placement = "pane.right"
title = "CI"
component = "ci" # a [[provides.components]] name
data = { file = ".ci/status.json" } # or "$session", "$cost", "$git", "$tasks"componentnames a component this manifest declares. The host shows it at session start and keeps its data current.datais a workspace file ({ file = "…" }, relative to the workspace) or a value the host holds. With nodata, the schema's defaults alone fill it.- A file source needs
[requires] readcovering the file.
[provides.actions.<name>]
What a pressed button, a chosen row or a submitted form in a declared component does. Exactly one key:
[provides.actions.explain]
send = "Explain why CI failed, from .ci/status.json" # a message to the agent, as the extension's
[provides.actions.rerun]
command = "/ci rerun ${value}" # an extension's slash command; ${value} = the chosen row's key| Key | Does |
|---|---|
send | Sends the text to the agent as the extension's message, never as the person's. Needs "run.send" = true under [requires]. |
command | Runs the slash command, starting with /. Only commands that installed extensions' tools register; never the client's built-ins (/model, /theme). |
${value} in either is replaced by the value that came with the action: a string as is (a row's key, a path), an object or a list as compact JSON (a form's values), nothing when there is none. It is text only, never a shell: a command still goes through the command registry. A value over 4 KiB is refused; send a key or a path instead (Actions). A code extension gets its actions as ui/event instead and needs no [provides.actions] (Show things: placements).
[requires]
What the extension asks for, by aspect. Each key takes true (the whole aspect), false (nothing) or a list of names or patterns:
| Key | Asks for |
|---|---|
read · write | Paths, such as "$WORKSPACE/**". |
spawn | Programs it may start, such as "git". |
net | Hosts it may reach. |
creds | Named credentials. |
mem.read · mem.write | Memory scopes. |
Install shows these requests and you grant or deny each. A denied request disables only the tools that need it.
[grants]
What a client package is handed beyond [requires]:
[grants]
client = ["draw", "consent", "tty"] # also: handoff| Grant | Lets it |
|---|---|
draw | Receive frames and send intents. |
consent | Answer a consent prompt. |
tty | Be handed the terminal. |
handoff | Move a session to another machine. |
[process]
Required for runtime = "process":
[process]
command = "bin/my-ext" # relative to the extension's folder, or on PATH
args = ["--stdio"]
protocol = "orrery-ext/1"
env = { RUST_LOG = "warn" }Declared extensions: runtime = "none"
An extension with runtime = "none" has no process and no code. The host shows its placements as components, feeds their data, and runs their actions. The whole guide is Show things: components.
It may provide only what the host draws or runs itself: [[provides.components]], [[provides.placements]], [provides.actions], [[provides.keys]], [[provides.elements]] and skills. Anything else (tools, providers, a client) is refused at load, naming what needs code. A [process] table is refused too.
[listing]
Optional. Only the extension gallery reads it.
| Key | Meaning |
|---|---|
image | A card image: an https:// URL or a path inside the package. |
homepage | The project's page, https:// only. |
Limits
- Components, placements and actions are checked at load: a name declared twice, a structure given both inline and as a
file(or neither), aschemathat is not an object, a placement naming an undeclared component or a host value that does not exist,datawithoutcomponent, an action with both or neither ofsendandcommand, and acommandnot starting with/are each refused, naming the key and the fix. - A placement whose
datafile[requires] readdoes not cover is refused at load, with thereadline to add. - The structure itself is checked against the catalog when the session starts, not by
orrery ext test. A refused one is drawn as its refusal, in its placement. - A structure
fileis read once, at session start. A change to it shows in the next session. - An action a structure names but
[provides.actions]lacks is found only when it is pressed: a notice names the table to add. [provides.actions]is read only forruntime = "none". A code extension's actions go to its own process.
Errors
A manifest that does not load names its file and what to write instead. Check one without a session:
orrery ext test ./my-extension