Skip to content

Capability Authoring Reference

The complete grammar and authoring rules. This mirrors <Runtime Home>/specs/capability-spec.md, which ships inside the binary and is refreshed with every version — when the two disagree, the file in your Runtime Home wins, because it describes the binary you actually have.

Writing your first capability?

Read Create a Capability instead — it walks the whole sequence in order, from finding operations to sharing the result. Come back here for the details.

Grammar

```runtime
version: v1

inputs:
  <name>:
    description: <plain-English description>
    required: true|false

workflow:
  - provider: <registered provider>
    args: [<operation word>, ..., <argument>, ...]

  - binary: <allowed binary>
    args: [<positional arg>, ...]
```
Key Level Required Meaning
version top yes Spec version this block was authored against
inputs top no Named parameters, referenced as ${name} in any step's args
workflow top yes Ordered list of steps, executed in order
provider step one of A registered Provider (github, files)
binary step one of A binary in allowed_binaries
args step yes Positional arguments, exactly as typed on the CLI
description input no What this input is for
required input no Whether execution refuses to run without it

Each step sets exactly one of provider or binary — never both, never neither.

These are the only keys

The parser rejects anything it does not recognize, naming the offending key and its line number.

transport: rest        ✗ not a key — the provider owns that decision
steps:                 ✗ it is `workflow:`
command:               ✗ from the retired command registry
capability:            ✗ there is no capability step

This strictness is the point. Before it, transport: rest on a step or steps: instead of workflow: validated clean while doing nothing — a file that looked correct and silently skipped its work.

args are the CLI, sequenced

A step's args are exactly the words you would type after runtime <provider>, split into a list.

On the command line In a capability
runtime files read ./a.txt provider: files
args: [read, ./a.txt]
runtime files write ./a.txt hello provider: files
args: [write, ./a.txt, hello]
runtime github repo view cli/cli provider: github
args: [repo, view, cli/cli]
runtime github repo list acme per_page=100 provider: github
args: [repo, list, acme, per_page=100]
runtime command run gh release upload v1 ./bin binary: gh
args: [release, upload, v1, ./bin]

This is the same surface, just sequenced inside a file instead of typed one command at a time.

Discovering operations

Do not guess at operations. Every provider publishes its full surface, and that published list is the authority:

runtime github --help
runtime files --help

The help output lists every operation, its argument form, and the transport the provider chose for it. The transport column is information, not a choice.

The rules

1. Never hardcode auth

Every step already goes through the Auth Engine via the provider or binary it names. A capability never embeds a token, credential, or auth flow of its own.

2. Never assume a Runtime Context beyond what's active

If a workflow genuinely needs a specific org, project or namespace, declare it as an input:

inputs:
  organization:
    description: GitHub organization to audit
    required: true

workflow:
  - provider: github
    args: [repo, list, "${organization}"]

Many operations already fall back to the active Runtime Context on their own — let them where the value really is where you are rather than what this run is about.

3. Ask when a required input is missing

Don't invent a placeholder and execute anyway. capability execute refuses to run with a missing required input; respect that at authoring time too.

4. Only reference what the runtime can execute

A step's provider must be registered and its args must name a real operation of that provider. A binary must already be in allowed_binaries.

5. Never depend on a transport

Write provider: github / args: [repo, list], never "the REST one". If you need a specific wire protocol, the provider is missing an operation — add the operation.

6. Don't finish until inputs are resolved

A capability referencing ${organization} isn't done until the author knows where that value comes from.

Input substitution

${name} substitution is literal text replacement, performed before execution.

inputs:
  path:
    description: Where to write
    required: true

workflow:
  - provider: files
    args: [write, "${path}", "hello"]
runtime capability execute my-cap --input path=./notes.txt

An unsupplied optional input stays literal

An input you declare but do not supply remains in the arguments as the literal string ${name}. That is why every shipped example marks its inputs required: true. Prefer required: true unless you have a concrete reason not to.

Passing a tool's own flags

Because a CLI-backed operation forwards arguments verbatim, a capability may pass that tool's own flags — including output flags:

- provider: github
  args: [pr, list, --json, "number,title,state"]

This is not naming a transport. You are passing arguments the operation accepts; the provider still owns how it delivers them.

For the runtime's own output format, use the global flag at execution time rather than inside the file:

runtime --output json capability execute my-cap --input ...

Composition: there is no capability: step

A capability cannot invoke another capability. There is no capability: step, and runtime is not an allowed binary — so a binary: runtime step fails validation too.

Large workflows inline the smaller ones they re-derive, and declare a Lineage section in the prose naming what was inlined:

## Lineage

Re-derives:
- `github/repo-health` — steps 3–5
- `files/scaffold-service-docs` — steps 9–12

The prose has no effect on execution. It exists so a reader can tell what a long workflow was assembled from, and so a change to a source capability has a findable set of dependents.

Worked example

Turning an ad-hoc audit into a capability:

# Repository standards audit

Answers "what do we own, and does this repo meet standard?"

## Lineage

Re-derives `github/repositories` for step 1.

```runtime
version: v1

inputs:
  organization:
    description: GitHub organization to audit
    required: true
  repository:
    description: Repository to inspect, as <owner>/<repo>
    required: true

workflow:
  - provider: github
    args: [repo, list, "${organization}", per_page=100]

  - provider: github
    args: [repo, summary, "${repository}"]

  - provider: github
    args: [api, GET, "/repos/${repository}/community/profile"]
```
runtime capability validate ./audit.md
runtime capability execute ./audit.md \
  --input organization=my-org \
  --input repository=my-org/payments-api

Note what the capability does not say: which transport serves each step. Step 1 happens to go over REST, step 2 over GraphQL, step 3 over REST — the provider decides, and can change its mind in a later runtime version without breaking this file.

Known limitations

Worth knowing before you design around them:

Limitation Consequence
No mkdir operation files write fails when parent directories are missing — create the path some other way first
files delete denied by default policy Use git rm for recoverable removal, or change policy deliberately
No encoding primitive Base64 payloads must be written literally in the file
Execution stops at the first failure Capabilities are not transactional — earlier steps have already run
No loops, no conditionals, no branching A capability is an ordered list. Complexity belongs in what you compose, not in control flow
No capability-to-capability calls Inline and declare Lineage

These are properties of a deterministic execution format, not a backlog. A workflow that needs branching is usually two capabilities and a decision.

Validation

runtime capability validate <path|name>

Reports every problem found, not just the first. See Validate & Execute.