Connector modes
RUNNER_CONNECTORS decides where tool answers come from. It’s the variable that causes the most
confusion during installation, because the default answers something, and something looks like
working.
synthetic: the default
Section titled “synthetic: the default”A deterministic built-in connector with a 3-operation seed, whose shapes do not match the real connectors. The real catalog has roughly 190 operations.
It serves exactly one purpose: proving boot, handshake, and dispatch without credentials.
real: your sources
Section titled “real: your sources”Registers the real connectors, with credentials read from the secret store, and enables the full PII redactor.
RUNNER_CONNECTORS=realEvery connector is lazy. It’s instantiated on first use, reading its own keys. A missing key only
makes those operations answer auth_error. Everything else keeps working. You don’t need every
credential to boot.
The served set is secret-aware: a connector whose required keys are absent drops out of the set
announced to the control-plane, and the signal for that is a connector not served line in the boot
log.
demo: the whole catalog, no credentials
Section titled “demo: the whole catalog, no credentials”RUNNER_CONNECTORS=demoBrings up a complete fictional environment. The manifests are derived from the real ones, with
the same ids (aws, datadog, github, …), the same operations, and secrets/egress zeroed out;
the handlers resolve from a fixture store with time-shift, so the planted incident always just
happened.
Properties worth knowing:
- An operation with no fixture answers empty but
ok, never an error. healthCheckis always green.- The ids are the real ones, not
demo. That’s deliberate: ademoid would make the agent-surface connector gate block every tool for being outside the served set. catalogHashstays intact: a manifest is not a wire contract.
This is the mode used for demos and for the consistency CI.
Comparison
Section titled “Comparison”synthetic |
demo |
real |
|
|---|---|---|---|
| Credentials | none | none | yours |
| Operations | 3 (seed) | whole catalog | whole catalog |
| Shapes match production | no | yes | yes |
| PII redaction | field-only | field-only | full |
| What for | boot and handshake | demos, CI | production |
Isolation mechanisms
Section titled “Isolation mechanisms”Orthogonal to the above. RUNNER_CONNECTOR_MECHANISMS (CSV, default native) chooses how a
connector executes:
native: inside the runner’s process. This is the mode for the connectors shipped with the product.sidecar: an OS-isolated subprocess, with secrets and egress mediated through host calls. It’s the only mechanism that actually enforces the egress allowlist.wasm: a seam; a spike validates the model.
The runtime’s four guarantees
Section titled “The runtime’s four guarantees”Independent of mode, the ConnectorRuntime upholds:
- Scoped secrets: each connector sees only its own.
- Egress allowlist: real under
sidecar, declaratory undernative. - Conformance: a suite validating the connector against the operation contract.
- Declared-field redaction: the manifest’s
sensitiveFields.
An invariant that fails at boot
Section titled “An invariant that fails at boot”Two connectors may not declare the same operation. The runtime validates manifests in the constructor and fails at boot:
op "metrics.getServiceLatency" claimed by both datadog and grafanaThat’s desirable, not a bug: execute(op) has to know deterministically where to dispatch.
Arbitration happens before the runtime. See Observability.
Writing your own connector
Section titled “Writing your own connector”Start with packages/connector-sdk (defineConnector + runConformance). The model conformance
suite is apps/runner/tests/connectors/grafana-conformance.test.ts, which covers both a populated
and an empty scenario.
If your connector serves a capability that already has an owner, it has to go through arbitration, so don’t add it directly to the real-connectors array.