Plugin connections
Declare external capabilities and credential contracts.
This page documents the runtime connection contract used by plugin
implementers. MD-first agents select connection providers by plugin ID; they
do not author root connections/ files. All definition examples below belong
inside a local or published plugin. See
MD-First Agents.
Connections declare external capabilities and credential requirements. Tokens used to authenticate a connection stay outside the agent folder, model context, tool arguments, and tool results. A trusted credential source may transfer a value directly to a trusted sink without exposing the intermediate string. Short-lived access credentials enter a sandbox only when a connection declares trusted materialization and the run explicitly requests it.
Configuration may be contextual. Credentials are capability-scoped. See Configuration And Credentials for the complete lifecycle and transport examples.
The declaration and implementation live in one published or local plugin. Each subagent resolves its own plugins and does not inherit a parent's external authority.
// plugins/github/ai.assemblyline/github.ts
import { adapter, defineConnection } from "@assemblyline-agents/core";
export default defineConnection({
description: "GitHub capability contract.",
provider: "github",
binding: adapter("env"),
scopes: ["repo:read"],
capabilities: ["issues:read", "pull_requests:read"],
subject: "user",
required: false
});Live Tool Connections
Use a protocol helper when a connection should expose tools through the deferred discovery path:
defineMcpClientConnection()defineA2AConnection()from@assemblyline-agents/a2adefineOpenAPIConnection()defineHttpApiConnection()defineSdkApiConnection()defineSandboxCliConnection()defineCredentialConnection()for host-only sandbox materialization with no tools
tool_search activates matching connection tools, which the model then calls
directly. Concrete remote schemas are not injected until discovery selects
them.
If deferred connection modules cannot load, tool_search records a failed,
recoverable tool call and returns the loader error to the model; it does not
count the failure as an available tool match. Partial searches may still return
healthy matches while reporting other connection loader errors separately.
The abstraction is the external capability and account, not its wire protocol.
MCP, A2A, OpenAPI, HTTP, provider SDK, sandbox CLI, and credential-only connections sit beneath the same connection
selection, access, approval, tracing, and subagent-scoping model. A sandbox CLI
connection runs its reviewed command inside the active agent sandbox so it can
see /files and /workspace; it does not launch the CLI on the gateway host.
Trusted SDK connections can also exchange bounded binary files without exposing the bytes or signed provider URLs to the model. A source connection stores the bytes in a run-scoped asset and returns only an opaque descriptor. A receiving connection consumes that descriptor in the same run, verifies its digest and size, and performs the provider upload host-to-host. Assets cannot cross run boundaries and are not a general model-readable filesystem.
Every live tool connection must declare tool-level access. Unclassified tools are not discoverable, and write matches take precedence over read matches:
export default defineMcpClientConnection({
url: "https://mcp.example.com",
description: "Example service.",
access: {
read: { tools: ["list_items", "get_item"] },
write: {
tools: ["create_item", "update_item", "delete_item"],
approval: "always"
}
}
});Install A Provider Plugin
Connection plugins package the provider's reviewed tool classification and enable that reviewed surface by default:
assembly-line add notion agent
assembly-line add slack agent --role connectionThe selected plugin enables its reviewed surface under the compiled access and
approval policy. Tools remain behind tool_search, so their schemas are added
only after discovery activates them. You do not copy connection tools into a
root tools/ folder.
Narrow or strengthen individual actions in agent.md:
capabilities:
notion:
connections:
notion:
disable: [delete_page]
approval:
create_page: never
update_page: alwaysThe plugin's reviewed read/write patterns remain the authority ceiling.
disable hides a tool entirely. approval changes only named tools and cannot
bypass host policy, connection authorization, or an absent grant.
Provider tools that match neither class stay hidden, including new upstream
tools that appear before the plugin reviews them.
Assembly Line does not create the Notion integration or OAuth application. The deployment owner supplies credentials and environment-based endpoint overrides. A different auth contract requires a reviewed plugin implementation. This same boundary applies to all official connection plugins.
Provider Events And Webhooks
Plugins with a reviewed event source enable their low-noise default events when
the connection is added. No webhook tool is added to tools/, and no event
adapter or provider schema enters model context. The adapter runs on the host:
it registers the callback and verifies and normalizes each delivery. Only an
explicitly authored matching automation stores the event in the durable inbox
and may start an agent run. Unmatched events are acknowledged and discarded
without model work or retained payload storage.
// plugins/mail/ai.assemblyline/agentmail.ts
import { defineAgentMailConnection } from "@assemblyline-agents/agentmail";
export default defineAgentMailConnection({
events: {
include: ["message.received", "message.bounced"],
resources: [{ inboxId: "inbox_123" }]
}
});Use include to replace the plugin defaults, exclude to remove events, and
resources to select provider objects such as projects, boards, calendars, or
tables. Use events: false to remove the provider subscription entirely:
export default defineAgentMailConnection({ events: false });Provider ingress alone never wakes the agent. Add an automation for the same connection and event to opt into execution and define its filter, target, message, or plugin lifecycle:
automations:
priority-email:
trigger: agentmail.message.received
connection: agentmail
filter:
priority: high
message: Handle this priority email.assembly-line deploy reconciles API-managed subscriptions after an active
hosted release. The runtime also reconciles on boot, after a user finishes
connection authorization, and periodically for expiring watches. Use the
operator commands for a manual run or a health check:
assembly-line connections wire agent --url https://agent.example.com
assembly-line connections check agent --url https://agent.example.comBoth commands use --token or ASSEMBLY_LINE_ADMIN_TOKEN. Providers that do
not expose webhook-management APIs return exact provider-console setup
instructions from wire; inbound verification and durable delivery still work
the same way. See the event-source matrix
for provider modes and resource requirements.
Plugin Transports
Every official connection plugin follows one of eight transports. The plugin catalog lists each plugin's configuration and credential names; each package README documents provider-specific setup.
| Transport | What runs where | Exemplars |
|---|---|---|
| A2A v1.0 | The runtime fetches an allowlisted Agent Card and uses its advertised JSON-RPC interface; each explicit remote skill becomes a deferred connection tool | Independently deployed Assembly Line agents and other conforming A2A agents |
| Hosted MCP (Streamable HTTP) | The provider's (or a developer-operated) MCP server; credential from a <PROVIDER>_MCP_TOKEN-style env var, custom header, OAuth flow, or host-redeemed one-time binding packet | Notion (above), Linear, AgentMail, Browser Use, Arcads, Margins, Mirror, Provenance |
| Direct OpenAPI | The provider's HTTP API called from the runtime using a bundled or referenced OpenAPI spec | Attio, SoundCloud |
| Direct HTTP API | The provider's HTTP API called from the runtime through a package-owned, reviewed operation list | Gmail, Google Calendar, Google Drive, Dropbox |
| Direct SDK API | A reviewed package-owned operation list called in-process against a provider API or official SDK | 1Password, Orgo |
| Stdio MCP | A packaged bridge or separately installed binary launched by the Assembly Line runtime host, trusted configuration, never model-chosen | FFmpeg, Peekaboo |
| Sandbox CLI | A provider CLI executed inside the active run sandbox with reviewed, individually quoted arguments | Higgsfield, Remotion |
| Credential only | The host authorizes and materializes provider credentials into the active run sandbox; no connection tools are exposed | GitHub App access for Git and gh |
For the receiving channel, task lifecycle, peer authentication, and discovery rules, see Agent-To-Agent (A2A).
One exemplar for each remaining transport:
// Inside the Gmail plugin entry: direct Gmail REST API with Google OAuth + PKCE.
// Enable the Gmail API; set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.
import { defineGmailConnection } from "@assemblyline-agents/gmail";
export default defineGmailConnection({
// Each Google service stores its own grant even when the OAuth app is shared.
});// Inside the 1Password plugin entry: direct API through the official provider SDK.
// Set OP_SERVICE_ACCOUNT_TOKEN for a service account scoped to shared vaults.
import { defineOnePasswordConnection } from "@assemblyline-agents/1password";
export default defineOnePasswordConnection({});// Inside the Dropbox plugin entry: direct HTTP API with OAuth Authorization Code + PKCE.
// Register one Dropbox app; set DROPBOX_APP_KEY and DROPBOX_APP_SECRET.
import { defineDropboxConnection } from "@assemblyline-agents/dropbox";
export default defineDropboxConnection({
// Use access: "read-only" to omit mutation tools and write OAuth scopes.
});// Inside the X plugin entry: private bookmarks and reviewed publishing through X API v2.
// Configure a confidential OAuth App; set X_API_CLIENT_ID and X_API_CLIENT_SECRET.
import { defineXConnection } from "@assemblyline-agents/x";
export default defineXConnection({
// Use access: "read-only" to omit publishing and the tweet.write scope.
});// Inside the SoundCloud plugin entry: direct OpenAPI with OAuth 2.1 PKCE.
// Register a SoundCloud app; set SOUNDCLOUD_CLIENT_ID and SOUNDCLOUD_CLIENT_SECRET.
import { defineSoundCloudConnection } from "@assemblyline-agents/soundcloud";
export default defineSoundCloudConnection({
// Reviewed tools are enabled by default.
});// Inside the FFmpeg plugin entry: install ffmpeg/ffprobe on the runtime host.
// All media paths stay inside workspaceRoot; the model never supplies flags or shell.
import { defineFfmpegConnection } from "@assemblyline-agents/ffmpeg";
export default defineFfmpegConnection({
workspaceRoot: "/workspace/media"
});// Inside the Higgsfield plugin entry: sandbox CLI transport.
// Install the official CLI in the sandbox image; run `higgsfield auth login`
// interactively inside each persistent, user-scoped sandbox.
import { defineHiggsfieldConnection } from "@assemblyline-agents/higgsfield";
export default defineHiggsfieldConnection({});Stdio and sandbox-CLI definitions are trusted application configuration: process command, arguments, and working directory come from the checked-in connection source, never from the model. A stdio child receives only portable process basics, literal non-secret factory settings, and the declaring connection's configuration and credentials. Local binaries and project dependencies must be provisioned on each runtime host where a stdio connection executes.
Connection files that project short-lived credentials must place every file
under /workspace/.assembly-line/credentials/. Workspace sync excludes this
reserved root, and the runtime rejects other materialization paths so access
tokens cannot enter workspace versions.
The GitHub App credential connection adds a run-aware host resolver. See GitHub App sandbox access for deployment-owned and user-owned installations, one-hour credentials, and GitHub-controlled repository and permission scope.
One-Time Binding Packets
Any connection can expose a host-side pairing redeemer by declaring
redeemPairingCode in its definition. Margins and Mirror ship one, and a
custom connection gets the identical flow by implementing that one function.
When a user pastes provider-generated binding instructions, the agent passes
the complete text through a pairing tool's secret field. The runtime
redacts the field from tool-call evidence, sends the one-time claim only to
the connection's configured provider origin, and persists the returned access
and refresh credentials in the host grant store. Do not run a packet's
shell-like line inside the sandbox or copy the claim into an agent file.
Two tools accept a packet:
pairis an always-visible core tool. It requires no prior discovery: a pasted packet always has a landing spot, even before a connection resolves.connectionmay be omitted when exactly one live connection supports pairing. When no connection can pair, or a connection cannot pair because its definition failed to resolve (missing package, unset env, platform mismatch),pairreports the real cause to the model and appends aconnection.pairing_unavailableevent for operators; the recovery path stays visible exactly when the connection is misconfigured.<connection>__pairis the synthetic per-connection tool advertised by connection discovery (tool_search), including while the connection is still unauthorized. Same host-side redemption path.
If a connection's definition module fails to load on the runtime host (for example the artifact is missing the connection's package), connection discovery reports that load error as a per-connection failure instead of silently omitting the connection and its pairing tool.
For Margins, the binding packet snapshots one page, one folder and its
descendants, or the whole workspace plus suggest or edit permission. Call
margins_status with the packet's expected fields immediately after pairing.
Assembly Line's connection policy remains an outer ceiling. Comments,
suggestions, page creation, and direct edits are reviewed write tools; set
access: "approval-required" if those actions should pause for approval.
Margins then applies its own scope, live-share, permission, stale-head, and
revocation checks.
Subagents receive only the connections contributed by plugins activated in
their own folder. A child that needs these providers declares them in
subagents/<name>/agent.md and pins them in that folder's plugins.lock:
---
description: Analyze sources, cut social video, and render approved outputs.
model: openrouter/openai/gpt-5.4-mini
capabilities: [arcads, higgsfield, ffmpeg, remotion]
---
Create the requested media and return the verified output artifacts.Missing Credentials At Runtime
When a tool call reaches a live connection that has no usable credential, the
runtime raises ConnectionAuthorizationRequiredError and turns it into a
structured, recoverable tool result for model-invoked calls:
authorization.requiredrecords the connection, reason, and complete private challenge for the callback path. The model-visible result includes the consent URL and instructions but excludes the OAuth state and session identifier. The model remains in control: it can use an available browser or computer connection with approved credentials, retry after consent, take another safe route, or finish the turn by telling the user exactly what is needed.- A required connection missing before the model turn emits
connection.requiredand becomes a loud context notice; it no longer parks the run before the model can reason. Direct/protocol-owned execution can still create a resumablewaiting_for_connectionrun when there is no model loop to receive the failure. - For OAuth and interactive authorization, completing the provider flow at
GET/POST /assembly-line/connections/callback(runtime.completeConnectionAuthorizationCallbackfor embedders) stores the grant. If the reply-capable conversation turn is still active, the model can retry in that turn. If the turn has finished, the callback enqueues a continuation at the end of the same conversation's FIFO mailbox. It never resumes beside another turn in that conversation. Callback handling is idempotency-claimed, so a replayed or double-fired callback never executes or enqueues the continuation twice. - Env-token connections are configuration, not authorization: a missing
<PROVIDER>_MCP_TOKEN-style variable surfaces as an explicitMissing <VAR>error naming the variable to set. - In
tool_searchresults, a connection needing authorization is reported withneedsAuthorization: truerather than silently omitted. Discovery and sandbox credential probing are read-only: they do not create durable authorization sessions.
Once a live connection is authorized, a rejected tool invocation is returned to the model as a failed tool result instead of failing the run. This lets the model correct invalid arguments or choose another tool. Assembly Line does not retry connection tools automatically; an undeclared live connection remains a terminal configuration error.
Legacy authorization waits are covered by recovery: an unexpired pending
session remains resumable, while an expired or missing session is marked
connection.unavailable so it cannot retain a conversation forever.
Callback-URL construction always emits /assembly-line/connections/callback.
Authorizing Before The First Run
Operator surfaces can start (or probe) authorization without parking a run:
GET /assembly-line/connections/authorize?connection=<name> on the node host
(runtime.beginConnectionAuthorization() for embedders). The route is
authenticated under the agent-control class and returns JSON. The dashboard
opens the returned consent URL, and the provider redirects to the public
callback:
{ "status": "authorize", "url": "…" }: send the user's browser here. A pending session's challenge is reused, so repeated calls never mint duplicate sessions and the same call doubles as a poll while consent is in flight. Expired sessions are pruned before a new one is created.{ "status": "connected" }: a usable grant already exists.{ "status": "unavailable", "reason": "…" }(409): the connection has no auth definition, an env-token variable is missing (Missing <VAR>), or a user-subject connection was called without an identity.
A connection's subject declares whose credential it is: "user" for a
per-person grant (personal context, private-surface only), and "workspace",
"installation", or "environment" for deployment-owned credentials that
work on every surface. An unannotated connection defaults to "workspace";
personal context is always an explicit opt-in. Plugins declare the right
subject for their auth shape, so plugin-backed connection files rarely set it.
Connections with subject: "user" key their grant by canonical principal.
When a channel maps users to an internal principal, include its issuer so the
minted grant is the one that run resolves. Embedders may pass the complete
principal directly to runtime.beginConnectionAuthorization(). Grants live in
the runtime's own store, so users authorize once per environment.
When the agent enables audienceIsolation, a public agent keeps these
personal connection declarations registered on every surface, but their tools,
pairing, authorization state, and materialized credentials exist only on a
private surface. Connection discovery in a shared conversation reports
requiresPrivateAudience: true instead of misclassifying the connection as
unauthorized. The account becomes usable and pairable when that same user
talks to the agent on a private surface such as a DM, and the resulting grant
is stored only under that user's canonical principal. Without
audienceIsolation (the default), personal connections work on every surface.
Connection auth and header resolvers also receive ctx.session.principal and
ctx.session.initiator. An agent-to-agent connection may use those claims to
mint a signed downstream assertion after explicitly trusting the caller; raw
OAuth tokens and connection credentials must not be forwarded.
MCP Transports
defineMcpClientConnection() is the Streamable HTTP form; transport: "http"
is optional. defineMcpStdioConnection() declares a static process with
transport: "stdio", command, optional args, cwd, and literal non-secret
environment settings. defineMcpRelayConnection() declares a static HTTPS
device relay with transport: "relay", url, a credential name declared in
plugin metadata, and an optional bounded timeout. Assembly Line uses the MCP TypeScript SDK for HTTP
and stdio, routes HTTP/relay traffic through the host request policy, and
launches stdio commands directly without a shell. Each registry keeps one lazy
client/process per connection and closes it during runtime shutdown.
Process- and device-backed MCP definitions are trusted application configuration. Dynamic connections remain ordinary URL-backed HTTP MCP only and cannot supply commands, arguments, working directories, process environments, relay credentials, or a paired device target.
Dynamic Connections
Dynamic connections are off by default. When enabled by
mutability.externalAccess in agent.md,
a tool calling ctx.connectionManager can persist a new URL-backed MCP, OpenAPI, or HTTP
connection definition into the durable connection registry.
Saving is approval-gated by default and restricted by allowedHosts. Credentials
route through host APIs or authorization flows, never model-visible tool input,
the agent folder, sandbox, or prompt.