This is the other half of declared connections. Use
defineConnection when you hold the credential and it is a static secret.
Use callService when the platform holds it and has to refresh it.1. Connect an account
Do this first — the code below returns404 until an account exists.
Each account is connected under a label, which is how your agent addresses
it. Use the CLI, or the API directly if you are scripting.
Connected once the account is authorized, so
you know it worked. It does not open a browser: the account often belongs to
somebody else, and this runs on servers as readily as on a laptop. Send them
the link and leave it waiting, or press Ctrl-C — the connection is unaffected.
For minting several links at once, --no-wait prints the link and exits.
--json does the same and is the one to script against.
Omitting the label connects it as default, which is what the examples below
assume. Calls do not need a label when exactly one eligible account is
connected. When several accounts are eligible, pass the label to select one;
otherwise the call returns 409 connection_alias_required and lists them.
The provider segment in the URL is the grant, not the service — google for
gmail, calendar, drive and sheets; github for GitHub; and linear for Linear.
connection add remains an alias for connection connect. If consent was
revoked or the connected account must change, start a fresh OAuth flow without
changing the logical connection or its project attachments:
2. Attach the account to a project
By default a connected account is personal: calls resolve it from the person who started the session. That is useful in the playground, but channel sessions such as Slack have a channel principal rather than the project owner’s user identity. Attach a connected account when it should be the project’s shared service credential:useService(). The session principal is still retained as the
actor for session ownership and audit; it no longer chooses the credential.
Detach removes only the project grant. It does not disconnect the underlying
OAuth account:
A connection that is not yet
connected is re-checked with the provider each
time it is listed, so pending means what it says. A connected account
is not re-checked: if someone revokes access at the provider, it keeps reading
connected until the next call to it fails. Treat connected as “was working”,
not “is working”.--service <name> picks
one.
--json if you want to parse its output.
3. Declare the service
useService takes a literal string, read out of your source at build time. It
puts the service in the capability manifest, so what your agent can reach is
reviewable without running it, and it asks the deployment for that grant —
without it, listServices() returns nothing.
The Google services share one grant; GitHub and Linear each have their own. A name outside that
list fails the build rather than the request.
There are two ways to reach GitHub, and they are for different jobs. Use
callService({ service: "github" }) to call the REST API on an account someone
connected. Use a GitHub App connection when the agent needs
to run git and gh itself — that one injects a token into the sandbox rather
than proxying requests.4. Call it from a tool
useService goes in the agent; callService goes in a tool. An agent renders
synchronously and cannot wait for a request.
messages.length is the size of the first page, not the total — real counting
means following nextPageToken. Most collection APIs behave this way.
callService returns the service’s own response — status, headers and body — as
fetch would, so a 403 for a missing scope stays distinguishable from a 404 for a
deleted message. Check response.ok; a model told only “it failed” will retry
forever.
Writes take the same shape:
POST:
response.ok and errors. The Linear connection accepts only POST /graphql;
other paths and methods fail at the broker.
Linear in sessions started from Linear
Which credential a call uses follows an explicit order. A session started from a Linear agent connection always uses that connection’s own Linear app. Otherwise, a project-attached Linear account wins; when the project has no Linear attachment, OpenComputer falls back to an eligible account owned by the session principal. In a session started from a Linear agent connection, the session belongs to the connection, andservice: "linear" resolves to
that connection’s own Linear app: the call acts as the agent, under the name
people delegate to, with the app’s token attached by the platform.
- No person’s connected Linear account is used in those sessions, and there
is no fallback to one; a
labelis ignored. - The deployment must declare
useService("linear"). - Only
POST /graphqlis accepted, as everywhere.
5. Several accounts
Accounts are connected and disconnected long after the artifact is built, so ask for them rather than naming them in source.
Only connected accounts are returned by default; pass
connectedOnly: false
for pending ones too. Connecting an account needs no redeploy — the next run
sees it, and a consent finished seconds ago is reconciled before the list is
answered.
Limits
A proxied request is not an unrestrictedfetch.
Other request headers are dropped, not rejected. The request is still sent
without them, so an API that changes behaviour on a header you set will act as
though you never set it. There is no error to catch.
Authentication headers are dropped for the reason they are on a declared
connection: the credential is the platform’s to attach, and a request that
could overwrite it could also send it elsewhere.
Both size limits raise an error rather than truncating, so an unexpectedly
large response fails loudly instead of arriving half-parsed. Page through large
collections rather than asking for them in one call.
When something fails
A
403 cannot be fixed from the agent. What a request may do is fixed by the
consent that created the connection; read scopes from listServices() to see
what was actually granted.