Skip to content

Connection protocol

Source candidate for named vendor-executor accounts (maia.connection/v1). The decision record is External brain and vendor executors.

Operations

MethodKindExposureReceipt
connection.createmutationhuman-onlyyes
connection.listreadunsupportedno
connection.showreadunsupportedno
connection.state.setmutationhuman-onlyyes
connection.capacity.setmutationhuman-onlyyes
connection.usage.showreadunsupportedno
connection.login.startmutationhuman-onlyyes
connection.gateway.createmutationhuman-onlyyes
connection.models.listreadunsupportedno
connection.detectreadunsupportedno
connection.system.previewpreviewhuman-onlyno
connection.system.confirmmutationhuman-onlyyes

Exposure is Agent-definition eligibility, not a grant. Only an authenticated operator without an Invocation attachment may call these operations.

Record

  • executor is codex-cli, claude-code or gateway (below).
  • configRoot is { kind: "maia-managed", path } or { kind: "system-default" }. Callers choose only the kind; Node derives the managed path under its private state directory, so a client can never point an account at an arbitrary path. A system-default root means the vendor variable is unset and the user's normal vendor login is reused.
  • Custody stays with the vendor CLI. The record never carries a token, and Node never reads the vendor credential file or Keychain entry.
  • maxConcurrentSessions is 1..64 (Node defaults to 2). connection.capacity.set changes it at an exact revision; a lower cap does not stop running Sessions, it only refuses new admissions until enough of them end.
  • limitedUntil is a vendor-reported availability window, separate from login validity; it is null until an executor records a limit.
  • revision starts at 1 and advances by one per state change. Records are disabled, never deleted.

Usage and sign-in

  • usage is the last snapshot Maia read for the account: bounded windows (session, weekly or other, usedPercent 0–100, optional resetsAt and windowMinutes), optional vendor resetCredits, optional account (email, plan) and, instead of windows, unavailable with a reason. connection.usage.show returns the record with its snapshot and, with refresh: true, reads the vendor first. Windows are vendor reports, not a Maia grant; Node admission still uses state, limitedUntil and the cap.
  • connection.login.start begins the vendor's own sign-in for a Maia-managed root and returns what the operator must open or type (authUrl, or userCode plus verificationUrl) with a loginId and expiresAt. The vendor completes the login inside its root; Maia never sees the credential. Today only codex-cli supports it. A Claude Code account signs in with claude auth login run for its own config root, which keeps one Keychain login per root; Maia never stores or reads a vendor credential.

Installed CLIs and setup

  • connection.detect takes an optional upkeep flag and returns both executors, Claude Code first. Without the flag the result is the v1alpha1 shape older strict readers decode; upkeep: true adds each installed executor's upkeep facts (approved build launches, newest version, update policy, proposal). Each executor carries: binary (found, absolute path, onNodePath, a dotted version), auth (vendor-login, custom-endpoint, none or unknown), an optional accountKind the vendor's status reports (such as claude.ai or chatgpt, never an email), an endpoint (host and credential: helper or env-key) exactly for a custom endpoint, the system-default connection if one exists, and executableApproved. It is a read-only coordinator tool (connection_detect). The endpoint may include a bounded hint command for registering a skipped Claude endpoint as a gateway; the same endpoint is carried by the setup preview. This optional field extends v1alpha1: older strict readers reject results that include it, so update Node and clients together. Credentials and helper commands are never included; unsafe URLs use a <url> placeholder. An installed Codex also carries an optional workerPrompt (ok, failed or inconclusive): whether its prompt render still drops the sections the worker launch keys remove. It extends v1alpha1 the same way.
  • connection.system.preview takes a commandId and an optional maxConcurrentSessions and returns per executor either a skip reason or the planned connection (create with name and cap, or existing with its ID, name and current cap) and executable (approve or existing), with a one-minute proof, the inputDigest, the actor, the expiry and, when the request gave one, the same maxConcurrentSessions, so a piped preview carries every field its confirmation repeats.
  • connection.system.confirm repeats commandId, maxConcurrentSessions, inputDigest and proof. Node claims the proof once, re-detects and refuses any change to the previewed steps, then for each executor approves the executable with integration.plan/apply and creates or reads its Connection, under command ids derived from the setup command. An approval counts only for the binary installed now. The result lists each used Connection with the receipts this command caused; repeating the confirmed proof replays it as duplicate, and a proof another confirmation claimed fails retryably, so setup previews again.

Gateway Connections

  • executor: "gateway" marks an AI gateway (an OpenAI- or Anthropic-compatible API with its own accounts and models) that any executor can use. The record adds gateway: { baseUrl }, always has a Maia-managed root, and never has limitedUntil or usage: the gateway keeps its own quotas.
  • baseUrl is https://, or http:// to a loopback host (localhost, 127.x.x.x, [::1]), in canonical form: no credentials, query, fragment, dot segments, default port or trailing slash; at most 2048 characters.
  • connection.gateway.create takes name, baseUrl, the apiKey (one line of 8 to 4096 printable ASCII characters) and an optional maxConcurrentSessions. The key is a creation input only: no record, result, event or receipt carries it, and the request digest excludes it. The result's keyCustody is stored when this call stored its key and kept when an earlier call already had.
  • connection.models.list reads the gateway's /v1/models now, in OpenAI or Anthropic form, and returns at most 512 model ids (truncated and omitted report what it left out). A model id matches ^[A-Za-z0-9][A-Za-z0-9._:/@-]{0,255}$.
  • A Session on a gateway names connectionId, the executor kind and optionally a model; session.executor.model records it. A vendor account refuses a model or another executor kind.

Compatibility

  • Names match ^[a-z][a-z0-9-]{0,62}$ and are unique per Node.
  • At most one system-default Connection exists per executor.
  • Every object rejects excess properties. Results bind the receipt to the exact Connection, command, method and aggregate revision.

Imported from Maia OS docs at a2175bb