Assembly LineDocs

Plugin connections

Declare external capabilities and credential contracts.

Edit

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/a2a
  • defineOpenAPIConnection()
  • 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 connection

The 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: always

The 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.com

Both 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.

TransportWhat runs whereExemplars
A2A v1.0The runtime fetches an allowlisted Agent Card and uses its advertised JSON-RPC interface; each explicit remote skill becomes a deferred connection toolIndependently 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 packetNotion (above), Linear, AgentMail, Browser Use, Arcads, Margins, Mirror, Provenance
Direct OpenAPIThe provider's HTTP API called from the runtime using a bundled or referenced OpenAPI specAttio, SoundCloud
Direct HTTP APIThe provider's HTTP API called from the runtime through a package-owned, reviewed operation listGmail, Google Calendar, Google Drive, Dropbox
Direct SDK APIA reviewed package-owned operation list called in-process against a provider API or official SDK1Password, Orgo
Stdio MCPA packaged bridge or separately installed binary launched by the Assembly Line runtime host, trusted configuration, never model-chosenFFmpeg, Peekaboo
Sandbox CLIA provider CLI executed inside the active run sandbox with reviewed, individually quoted argumentsHiggsfield, Remotion
Credential onlyThe host authorizes and materializes provider credentials into the active run sandbox; no connection tools are exposedGitHub 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:

  • pair is an always-visible core tool. It requires no prior discovery: a pasted packet always has a landing spot, even before a connection resolves. connection may 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), pair reports the real cause to the model and appends a connection.pairing_unavailable event for operators; the recovery path stays visible exactly when the connection is misconfigured.
  • <connection>__pair is 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.required records 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.required and becomes a loud context notice; it no longer parks the run before the model can reason. Direct/protocol-owned execution can still create a resumable waiting_for_connection run 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.completeConnectionAuthorizationCallback for 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 explicit Missing <VAR> error naming the variable to set.
  • In tool_search results, a connection needing authorization is reported with needsAuthorization: true rather 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.

On this page