Connectors
Route relayed work to builtin or custom connectors.
A connector is the backend that runs a relay step. Three are builtin:
| Connector | Provider |
|---|---|
claude-code | anthropic |
codex | openai |
cursor-agent | gemini |
You can also register custom connectors that run your own command.
Where it lives
Connectors are configured under relay in the config file. The block has four keys:
| Key | What it controls |
|---|---|
default | The connector used when nothing more specific matches. A builtin name, the auto sentinel, or a custom name. Defaults to auto. |
roles | Per-role overrides. Keys are researcher, implementer, reviewer. |
circuits | Per-flow overrides, keyed by flow id. |
connectors | The custom connector registry. |
roles and circuits reference a connector by kind (builtin or named). A named reference must point at a connector registered under connectors.
Example
relay:
default: auto
roles:
researcher:
kind: builtin
name: codex
implementer:
kind: builtin
name: claude-code
circuits:
review:
kind: named
name: my-linter
connectors:
my-linter:
kind: custom
name: my-linter # must match the registry key
command: [my-linter, --json] # argv list, no empty elements
prompt_transport: prompt-file
output:
kind: output-file
capabilities:
filesystem: read-only
structured_output: jsonCustom connectors
A custom connector descriptor takes these fields:
| Field | Value |
|---|---|
kind | custom |
name | kebab-case (^[a-z][a-z0-9-]*$); cannot reuse a builtin name or auto |
command | argv list, at least one element, no empty strings |
prompt_transport | prompt-file |
output | { kind: output-file } |
capabilities.filesystem | read-only (the only value accepted for a custom connector) |
capabilities.structured_output | json |
These rules are enforced at parse time:
- Custom connectors must declare
filesystem: read-only. Writable custom workers are not yet supported. - The registry key and the descriptor
namemust match.
Because a custom connector is read-only, it cannot fill the implementer role: that role writes. Use a builtin for implementer; use custom connectors for researcher and reviewer.
The relay block parses strictly: unknown keys are rejected.
Power tier tables
The power dial never names models. Each connector
carries a tier table that translates low, medium, and high into a
concrete model or reasoning effort. Two of the builtins ship with defaults:
claude-code maps the tiers to Anthropic's small, middle, and big model
aliases; codex maps them to reasoning effort. cursor-agent and custom
connectors have no table until you declare one under the top-level
power_tiers key:
power_tiers:
my-ollama:
low: { model: { provider: custom, model: qwen3-coder } }
medium: { model: { provider: custom, model: qwen3-coder-plus } }
high: { model: { provider: custom, model: qwen3-max } }A declared tier overrides only that tier of that connector; shipped defaults fill the rest. Without a table, the dial is inert for that connector.
What a custom command receives
Circuit appends two paths as the final two arguments of your command: the
prompt file to read and the output file to write. The subprocess inherits
Circuit's environment and working directory, plus the resolved selection:
| Variable | Value |
|---|---|
CIRCUIT_RELAY_MODEL | The materialized tier's model id. |
CIRCUIT_RELAY_MODEL_PROVIDER | anthropic, openai, gemini, or custom. |
CIRCUIT_RELAY_EFFORT | The effort tier, when one is set. |
This is the seam for local workers: wrap a local agentic CLI in a small
script, point power_tiers.<name> at your local model names, and the power
dial drives local model choice with no engine changes.