Skip to content

One definition, every surface

Each operator command is written once as a typed definition; chat, CLI, HTTP and MCP are derived from it, so no surface can drift (decision 0008).

What "once" looks like

The args and options schema is the one source for a valid call, the --help text, the MCP inputSchema, and every surface's validation error. The reference tables are generated from the same definitions and checked by CI (Reference).

One pipeline underneath all four

An adapter translates its request into {args, options, caller} and the result back out. It holds no command logic or validation.

  • The caller is resolved by the adapter, never read from the request. Slack derives it from the event (slack:U…); HTTP from the identity the dashboard gate verified. Nothing upstream of invoke() reads an identity field from the payload, so a scope rule is enforced in one place (decision 0004).
  • One error vocabulary. A malformed call is invalid_input everywhere; a caller without the scope is unauthorized, decided before parsing, so a refusal reveals nothing about a well-formed call.

Commands versus runs

The registry covers operator commands (config, runs, repo, memory, friction, schedule, deploy, env) and nothing that starts a model. Agent runs go through the dispatcher from a message-shaped input: the CLI's ask, MCP's dispatch, a Slack message. Those are channels beside the registry (decision 0002).

Commands are scope-authorized and synchronous to a typed result; a run is long-lived, budgeted and side-effecting, with its own gates. So /api/config.show behind a read scope is always cheap.

For a developer

A new command is one schema and one handler. It appears on every surface with no further code, and a conformance suite drives every command through every surface, so a misfit fails loudly.