Connection protocol
Source candidate for named vendor-executor accounts (maia.connection/v1). The
decision record is External brain and vendor executors.
Operations
| Method | Kind | Exposure | Receipt |
|---|---|---|---|
connection.create | mutation | human-only | yes |
connection.list | read | unsupported | no |
connection.show | read | unsupported | no |
connection.state.set | mutation | human-only | yes |
connection.capacity.set | mutation | human-only | yes |
connection.usage.show | read | unsupported | no |
connection.login.start | mutation | human-only | yes |
connection.gateway.create | mutation | human-only | yes |
connection.models.list | read | unsupported | no |
connection.detect | read | unsupported | no |
connection.system.preview | preview | human-only | no |
connection.system.confirm | mutation | human-only | yes |
Exposure is Agent-definition eligibility, not a grant. Only an authenticated operator without an Invocation attachment may call these operations.
Record
executoriscodex-cli,claude-codeorgateway(below).configRootis{ 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.
maxConcurrentSessionsis1..64(Node defaults to 2).connection.capacity.setchanges it at an exact revision; a lower cap does not stop running Sessions, it only refuses new admissions until enough of them end.limitedUntilis a vendor-reported availability window, separate from login validity; it isnulluntil an executor records a limit.revisionstarts at1and advances by one per state change. Records are disabled, never deleted.
Usage and sign-in
usageis the last snapshot Maia read for the account: boundedwindows(session,weeklyorother,usedPercent0–100, optionalresetsAtandwindowMinutes), optional vendorresetCredits, optionalaccount(email,plan) and, instead of windows,unavailablewith a reason.connection.usage.showreturns the record with its snapshot and, withrefresh: true, reads the vendor first. Windows are vendor reports, not a Maia grant; Node admission still usesstate,limitedUntiland the cap.connection.login.startbegins the vendor's own sign-in for a Maia-managed root and returns what the operator must open or type (authUrl, oruserCodeplusverificationUrl) with aloginIdandexpiresAt. The vendor completes the login inside its root; Maia never sees the credential. Today onlycodex-clisupports it. A Claude Code account signs in withclaude auth loginrun 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.detecttakes an optionalupkeepflag and returns both executors, Claude Code first. Without the flag the result is thev1alpha1shape older strict readers decode;upkeep: trueadds each installed executor'supkeepfacts (approved build launches, newest version, update policy, proposal). Each executor carries:binary(found, absolutepath,onNodePath, a dottedversion),auth(vendor-login,custom-endpoint,noneorunknown), an optionalaccountKindthe vendor's status reports (such asclaude.aiorchatgpt, never an email), anendpoint(hostandcredential:helperorenv-key) exactly for a custom endpoint, the system-defaultconnectionif one exists, andexecutableApproved. It is a read-only coordinator tool (connection_detect). The endpoint may include a boundedhintcommand for registering a skipped Claude endpoint as a gateway; the same endpoint is carried by the setup preview. This optional field extendsv1alpha1: 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 optionalworkerPrompt(ok,failedorinconclusive): whether its prompt render still drops the sections the worker launch keys remove. It extendsv1alpha1the same way.connection.system.previewtakes acommandIdand an optionalmaxConcurrentSessionsand returns per executor either a skipreasonor the plannedconnection(createwith name and cap, orexistingwith its ID, name and current cap) andexecutable(approveorexisting), with a one-minuteproof, theinputDigest, the actor, the expiry and, when the request gave one, the samemaxConcurrentSessions, so a piped preview carries every field its confirmation repeats.connection.system.confirmrepeatscommandId,maxConcurrentSessions,inputDigestandproof. Node claims the proof once, re-detects and refuses any change to the previewed steps, then for each executor approves the executable withintegration.plan/applyand 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 asduplicate, 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 addsgateway: { baseUrl }, always has a Maia-managed root, and never haslimitedUntilorusage: the gateway keeps its own quotas.baseUrlishttps://, orhttp://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.createtakesname,baseUrl, theapiKey(one line of 8 to 4096 printable ASCII characters) and an optionalmaxConcurrentSessions. The key is a creation input only: no record, result, event or receipt carries it, and the request digest excludes it. The result'skeyCustodyisstoredwhen this call stored its key andkeptwhen an earlier call already had.connection.models.listreads the gateway's/v1/modelsnow, in OpenAI or Anthropic form, and returns at most 512 model ids (truncatedandomittedreport 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, theexecutorkind and optionally amodel;session.executor.modelrecords it. A vendor account refuses amodelor 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