Skip to main content

Adapters (Substrate Reference)

This page is the reference for consuming the substrate adapters that ship with Assembly Line. To discover and install plugins — including the full catalog and assembly-line add — start at Plugins.

Assembly Line adapters are deliberately small. gateway.ts chooses where the runtime runs and which durable services it uses; channel files choose how external events become Assembly Line turns; sandbox files choose where isolated code and shell work runs. These choices are independent.

Adapters are substitutable substrate: each role (channel, sandbox, blob, state, scheduler, gateway/deploy) has a generic contract with interchangeable providers, so the same agent runs unchanged on different infrastructure. Capabilities are a separate tier. A capability is a single-vendor feature that gives an agent something new to do rather than somewhere new to run — it exposes that vendor's own surface and has no generic contract to swap behind. Capability packages live under capabilities/ (see Capabilities), still ride the same open provider seam, and describe themselves through provider metadata so tools like the no-code builder can scaffold them automatically.

Adapter support levels:

  • Supported means Assembly Line has a real runtime instantiation path, docs, and regression coverage in this repo.
  • Preview means the public helper, compiler metadata, and local regression coverage exist, but the adapter still needs live provider smoke coverage or more provider hardening before it should be announced as fully supported.
  • Planned means the docs may name the direction, but the adapter is not a production claim yet.

The current matrix is:

RoleSupportedPreviewPlanned
ChannelsSlack, Discord, Telegram, Microsoft Teams, Photon/Spectrum--
Sandboxeslocal dev/test, Docker, Daytona, E2BModal-
Blob storagelocal dev/test, R2, generic S3-compatible storage--
Durable statelocal dev/test files, Postgres for production, with Neon, Railway, Supabase, local, and custom presets-other database families
Schedulerlocal in-process loop, gateway-triggered cloud scheduler, Postgres-backed multi-worker loop--
Gateway/deploylocal, RailwayDocker, Fly, generic VPSprovider-managed VPS provisioning and other gateway families

Other database families, gateway families, and sandbox providers are not part of this initial adapter set.

Primary model engines are not an adapter role in this matrix. Pi remains the default. Separately, the Node host includes a preview openai-codex/* provider-prefix route backed by the official Codex app-server. That route is implemented in @assemblyline-agents/codex but is not provider-package registration and does not add a public harness: field to agent.ts.

Capabilities are tracked separately from the adapter roles above because they are not substitutable substrate:

CapabilitySupportedPreviewPlanned
Voice / telephony-LiveKit voice dispatch and SIP calls-

Provider Docs Used

The adapter shapes follow current provider docs for:

Gateway

Gateway adapters answer one question: where does the compiled Assembly Line runtime service run?

They do not choose your state, blob, sandbox, channels, or connections. Those are separate settings in the same gateway.ts file.

import { adapter, defineGateway } from "@assemblyline-agents/core";
import { neonPostgres } from "@assemblyline-agents/postgres";
import { r2Blob } from "@assemblyline-agents/s3";
import { dockerSandbox } from "@assemblyline-agents/docker";

export default defineGateway({
deploy: adapter("railway"),
runtime: adapter("node"),
state: neonPostgres(),
blob: r2Blob(),
sandbox: dockerSandbox()
});

Deploy target status:

  • Supported: adapter("railway") or railwayDeploy() runs the hosted Node runtime through the @assemblyline-agents/railway deploy publisher.
  • Supported: adapter("docker") or dockerDeploy() builds the compiled artifact as a Docker image through the @assemblyline-agents/docker deploy publisher and can optionally run it locally.
  • Supported: adapter("fly") or flyDeploy() generates fly.toml and publishes the artifact through the @assemblyline-agents/fly deploy publisher and flyctl deploy.
  • Supported: adapter("vps") or vpsDeploy() deploys to a named AMD64 Ubuntu 24.04/26.04 or Debian 12 host over fingerprint-pinned SSH. It manages per-agent containers, networks, storage, database access, secrets, Caddy routing, and transactional blue/green releases without mounting the Docker socket into an agent. Hetzner hosts can also be securely created or adopted through assembly-line hosts bootstrap.

Useful CLI flags:

assembly-line deploy --target docker --docker-image assembly-line/my-agent --serve
assembly-line deploy --target fly --fly-app my-agent --fly-region iad
assembly-line deploy --target railway --railway-project prj_x --railway-service svc_y
assembly-line deploy --target vps --vps-host production-eu --vps-domain agent.example.com --sync-secrets

Community Plugin Providers

Any npm package can supply a state, blob, sandbox, or deploy provider that agents select with adapter(kind, options, { package }) — see Authoring Plugins for the contract, preflight, and artifact-packaging behavior.

Scheduler

Schedules compile to registration metadata, but the scheduler adapter chooses where the clock lives.

import { adapter, defineGateway } from "@assemblyline-agents/core";

export default defineGateway({
scheduler: adapter("gateway")
});

Supported scheduler adapters:

  • adapter("local"): starts an in-process polling loop with the Node host. Use this for local development, tests, and simple single-process hosts.
  • adapter("gateway"): does not start a local loop. Use a platform cron, cloud scheduler, Durable Object alarm, queue worker, or gateway route to call GET or POST /assembly-line/automations/tick, or call runtime.runDueAutomations() from host code.
  • adapter("postgres"): starts the polling loop and coordinates duplicate workers through the Postgres state adapter's idempotency and dynamic schedule leases. Pair it with state: adapter("postgres").

For gateway-triggered production schedulers, set ASSEMBLY_LINE_SCHEDULER_SECRET and send it as Authorization: Bearer <secret> or x-assembly-line-scheduler-secret.

Capabilities

Capabilities live under capabilities/ and are single-vendor features, not substitutable adapters. They expose focused clients, tools, definitions, and connection metadata instead of pretending to implement an interchangeable runtime role. A no-code builder or catalog can use that metadata to render a plugin card and credential form without making the capability an agent engine.

Subagents And Model Routing

Every primary agent and child agent runs through Pi. Subagents are isolation and delegation boundaries, not engine adapters; their definitions may narrow the model, workspace, tools, and connections, while omitted models inherit the primary model.

@assemblyline-agents/codex also exports codexAgentHarness() for the Node host's preview primary-model route. It exposes Assembly Line tools to app-server as dynamic tools, keeps execution and approvals in the Assembly Line runtime, and persists the Codex thread id as opaque continuation state. Authentication stays inside the Codex CLI session. App-server reports whether that session is using ChatGPT or an API key; Assembly Line records the billing rail and provider token/credit snapshots without reading either credential. For Railway deployments, selecting an openai-codex/* primary model packages the official CLI, provisions persistent /data/codex storage, and supports direct remote device authentication through assembly-line auth codex; no OAuth token is copied into Railway variables.

The Pi/OpenRouter route records native token and charged-credit receipts, with generation-ID reconciliation when settlement is delayed. Codex reports per-turn tokens but not per-turn dollars; API-key cash is therefore reconciled as an OpenAI organization control total and is attributed to an agent only when an operator provides a dedicated project or API-key mapping.

LiveKit Voice

Assembly Line does not run realtime media inside the text-model runtime. Instead, @assemblyline-agents/livekit signs LiveKit server tokens, calls the LiveKit Agent Dispatch and SIP Twirp APIs, and lets an Assembly Line turn start or route a LiveKit voice session.

Use a tool when the parent agent should decide to dial:

// tools/start_call.ts
import { defineLiveKitOutboundCallTool } from "@assemblyline-agents/livekit";

export default defineLiveKitOutboundCallTool({
agentName: "support-voice",
outboundTrunkId: "ST_outbound"
});

Declare the connection when the agent or a Pi-backed subagent should receive LiveKit credentials and preflight requirements:

// connections/livekit.ts
import { defineLiveKitConnection } from "@assemblyline-agents/livekit";

export default defineLiveKitConnection();

The LiveKit agent named by agentName must be running in your LiveKit Agents worker. For outbound phone calls, Assembly Line dispatches that worker into a room and calls CreateSIPParticipant to dial the callee through your outbound SIP trunk. Incoming phone calls should be routed in LiveKit with SIP dispatch rules to the LiveKit agent worker; Assembly Line can still be used by that worker as an app/runtime layer, but the phone media path remains LiveKit.

This keeps the boundary explicit: LiveKit owns rooms, media, dispatch, and SIP; Assembly Line owns Pi reasoning, typed tool calls, and durable run state.

Required environment:

PurposeEnv
LiveKit server APILIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET
Default outbound dialingoptional LIVEKIT_OUTBOUND_TRUNK_ID
Default voice worker dispatchoptional LIVEKIT_VOICE_AGENT_NAME

Channels

Channel packages export one-line helpers for normal use. They verify provider auth, normalize the provider event into ChannelTurn, preserve provider IDs in metadata/delivery, and send the final reply through provider APIs.

After a deploy, point each channel's provider at the deployed ingress URL with:

assembly-line channels wire <agentRoot> --url https://your-service.example.com

It computes each channel's ingress URL from the compiled route table and, for Telegram, calls setWebhook directly (needs TELEGRAM_BOT_TOKEN, and uses TELEGRAM_WEBHOOK_SECRET when set). For providers that configure their endpoint in a console (Slack Request URL, Discord Interactions Endpoint, Teams messaging endpoint), it prints the exact URL to paste. Output is a structured ChannelWireResult[] (action: "set" | "manual").

// channels/slack.ts
import { defineSlackChannel } from "@assemblyline-agents/slack";

export default defineSlackChannel();
// channels/discord.ts
import { defineDiscordChannel } from "@assemblyline-agents/discord";

export default defineDiscordChannel({
gateway: true,
requireMention: true
});
// channels/telegram.ts
import { defineTelegramChannel } from "@assemblyline-agents/telegram";

export default defineTelegramChannel();
// channels/teams.ts
import { defineTeamsChannel } from "@assemblyline-agents/teams";

export default defineTeamsChannel();

Required channel environment:

ChannelRequired env
SlackSLACK_SIGNING_SECRET, SLACK_BOT_TOKEN, optional SLACK_BOT_USER_ID, optional SLACK_ASSISTANT_ENABLED
DiscordDISCORD_PUBLIC_KEY, DISCORD_APPLICATION_ID, DISCORD_BOT_TOKEN, optional DISCORD_GATEWAY_ENABLED, optional DISCORD_GATEWAY_INTENTS, optional DISCORD_BOT_USER_ID
TelegramTELEGRAM_BOT_TOKEN; TELEGRAM_WEBHOOK_SECRET is required outside devMode
TeamsMICROSOFT_APP_ID, MICROSOFT_APP_PASSWORD, optional ASSEMBLY_LINE_TEAMS_ALLOWED_TENANTS, optional ASSEMBLY_LINE_TEAMS_ALLOWED_SERVICE_URLS

Channel-owned ingress auth and attachment resolution

Channels declare their own production ingress-auth requirements and resolve their own provider attachments; the runtime stays a generic dispatcher.

  • ChannelDefinition.ingress.requiredSecretEnv is a list of any-of groups of env var names: production boot succeeds when every var in at least one group is set (for example Photon declares [["PHOTON_WEBHOOK_SIGNING_SECRET"], ["PHOTON_INGRESS_TOKEN"]]). The compiler stamps the declaration into CompiledChannel.metadata.ingress; in production the runtime refuses to boot when no group is satisfied, and in devMode it logs a warning instead. The built-in helpers (defineSlackChannel, defineTelegramChannel, defineDiscordChannel, defineTeamsChannel, definePhotonChannel) declare this automatically; custom channels can set ingress on their channel config and re-export the same shape as ingressAuth on the module.
  • ChannelModule.resolveAttachment(attachment, ctx) turns a turn attachment into a download request ({ url, headers, filename? }). The runtime performs the download, applies size/type limits and timeouts, and stores the blob; the channel owns auth lookups (Slack files.info, Telegram getFile, the Teams Bot Framework token flow, Photon bridge bearer headers) and host allowlists. Return undefined to fall back to a generic unauthenticated URL download.
  • Trust boundary: the runtime only calls resolveAttachment on the module of the channel that produced the turn, and only when the turn's declared provider matches that channel — a hostile attachment claiming another provider can never route to that provider's credentials. Inside a resolver, use attachmentTrustedForProvider(attachment, "<provider>") and attachmentRemoteUrl(attachment) from @assemblyline-agents/runtime to honor the per-attachment remote.trusted markers before attaching credentials.

Attachment materialization

Inbound files follow the same normalized ChannelTurn.attachments contract on every channel. Adapters should preserve provider file identity plus one of:

  • inline content (content, text, body, or base64 data)
  • a safe remote reference (url, downloadUrl, contentUrl, or remote: { provider, auth?, url })
  • provider-specific lookup metadata such as Telegram file_id

The runtime materializes remote attachments after the webhook ACK, stores the original bytes through the configured blob adapter, records them as read-only /files/original/... resources, and lists them in /files/manifest.json. Private download details and auth hints are stripped from model-visible attachment context after storage. Text and Markdown attachments read back as UTF-8; binary files remain byte-accurate for resource projection. ZIP uploads are also expanded when possible: the original archive remains available under /files/original/..., and safe entries are exposed as read-only resources under /files/extracted/<archive-name>/... for the core file tools. Unsupported, encrypted, oversized, or path-escaping ZIP entries are skipped or reported without dropping the original uploaded archive.

Stored PNG, JPEG, GIF, WebP, MP4, MPEG, MOV, and WebM attachments are additionally supplied to the primary harness as typed model media. Adapters should therefore preserve the correct MIME type instead of labeling every upload as application/octet-stream. The runtime never exposes private attachment URLs to the model; it reads the configured blob and gives the harness bounded base64 bytes. A harness sends complete video only when the selected model advertises native video support. Otherwise Assembly Line reports the limitation and does not sample frames unless the user explicitly requests that approximation.

Slack uses the Events API route /slack/events. It verifies the raw request body with Slack's signing secret, handles url_verification inline, returns a 2xx ACK for accepted events before model work, and uses Slack event_id as the delivery idempotency key. It starts turns only for intentional agent entry points: app mentions, user DM messages, and assistant-thread user messages when assistant mode is enabled. Delivery always uses the preserved Slack channel and thread target from the normalized turn.

Slack context augmentation runs after ACK and before default context bundle construction. It supplies the current conversation history plus up to three recent Assembly Line Slack conversations for the same user from the last 24 hours as short summaries and structured metadata. It does not fetch workspace-wide Slack history during ingress.

Agent communication channel status:

  • Slack and Photon/Spectrum are reference agent channels. Slack maps app mentions, DMs, and assistant-thread user messages into durable Assembly Line turns; Photon/Spectrum maps iMessage bridge events into the same lifecycle and adds native actions such as reactions, polls, app cards, and backgrounds.
  • Discord is an agent-oriented communication channel when Gateway ingress is enabled. Interactions still cover slash commands, components, modals, and autocomplete; Gateway ingress covers DMs, mentions, and thread/channel messages. Discord starts typing indicators for Gateway turns and delivers through either interaction responses or bot-token channel messages.
  • Telegram is an agent-oriented communication channel over Bot API webhooks. It supports messages, edited messages, callback queries, channel posts, business messages, forum topics, typing actions, inline keyboards, callback answers, media sends, and getFile attachment materialization.
  • Microsoft Teams is an agent-oriented communication channel over Bot Framework activities. It supports message activities, Adaptive Card invoke submissions, mention stripping, tenant/service URL constraints, typing activities, Adaptive Card replies, suggested actions, and protected attachment materialization.

Connections

Connection helpers remain available when agents need provider capabilities beyond receiving messages. Channels own inbound events and reply delivery; connections own typed provider capabilities, credential requirements, and remote tool discovery.

GitHub is connection-only: use it for repository, issue, pull-request, and workflow tools rather than as an inbound communication channel.

// connections/github.ts
import { defineGitHubConnection } from "@assemblyline-agents/github";

export default defineGitHubConnection();
// connections/teams.ts
import { defineTeamsConnection } from "@assemblyline-agents/teams";

export default defineTeamsConnection();

GitHub App connections require GITHUB_APP_ID and GITHUB_PRIVATE_KEY. Teams uses Bot Framework credentials.

Live smoke evidence for Discord, Telegram, and Teams is written locally under docs/internal/evidence/channels/ (a gitignored working directory). The root smoke scripts skip without credentials and point to those provider checklists when credentials are present.

Sandboxes

The sandbox adapter is acquired lazily when a tool or capability asks for a sandbox. Normal channel receipt, model turns without sandbox-backed tools, skill activation, memory reads/writes, and final delivery do not need to pay sandbox startup cost.

// sandbox/default.ts
import { dockerSandbox } from "@assemblyline-agents/docker";

export default dockerSandbox({
image: "node:22-slim",
network: "none"
});

Sandbox adapter status:

  • Supported: adapter("local") for trusted dev/test only.
  • Supported: adapter("docker") or dockerSandbox() for local container isolation, one container per acquired session, cleanup on dispose, and a physical /workspace container cwd.
  • Supported: adapter("daytona") for hosted Daytona sandboxes.
  • Supported: adapter("e2b") or e2bSandbox() for hosted E2B sandboxes.
  • Supported: adapter("modal") or modalSandbox() for hosted Modal sandboxes. Its JavaScript SDK, filesystem, lifecycle, readiness probe, image, tag, and snapshot bindings are compile-checked against the installed Modal SDK.

All hosted built-in sandbox adapters expose the same physical namespace: shells start in /workspace, absolute /workspace/... shell paths and provider file APIs address the same files, and create/connect/wake fail if that invariant does not hold. Docker uses its native container workdir, Daytona builds the configured image with WORKDIR /workspace, Modal extends its image and passes the native Sandbox workdir, and E2B idempotently provisions /workspace through its root command facility before returning to the template's ordinary command user. .. traversal is rejected. Recursive listings return canonical absolute paths and include contents for runtime persistence.

The filesystem contract is versioned in provider metadata, labels/tags, provider-safe names, runtime manifests, and sync jobs. A runtime never reconnects or restores a snapshot from an obsolete contract. The Local adapter is explicitly a trusted dev/test logical emulation over a host temporary directory; Docker is the local conformance path when physical /workspace semantics matter.

Dirty sandbox sessions are retained when async sandbox sync is pending: Docker stops the container, Daytona pauses/stops, and E2B pauses with configurable memory retention. Modal detaches retained sessions and terminates clean ones. Clean sessions are removed, deleted, killed, or terminated through the provider lifecycle API. The sync worker reconnects first and then calls wake()/start when a retained sandbox is warm or paused.

Hosted adapters do not silently fall back to local execution. Daytona local fallback exists only for explicit development/test opt-in with ASSEMBLY_LINE_ALLOW_LOCAL_SANDBOX_FALLBACK=true.

The local sandbox is for trusted dev/test execution. Production Node runtime construction rejects adapter("local") for sandboxes unless ASSEMBLY_LINE_ALLOW_LOCAL_SANDBOX_IN_PRODUCTION=true is set to acknowledge that the host process, filesystem, and network are not isolated. Docker defaults ASSEMBLY_LINE_DOCKER_NETWORK to none; Daytona supports ASSEMBLY_LINE_DAYTONA_NETWORK_BLOCK_ALL and allow/domain lists for explicit egress policy.

Provider env:

SandboxRequired envLifecycle and policy env
DockerDocker CLI/daemon availableOptional DOCKER_HOST, ASSEMBLY_LINE_DOCKER_NETWORK (defaults to none), ASSEMBLY_LINE_DOCKER_CPUS, ASSEMBLY_LINE_DOCKER_MEMORY, ASSEMBLY_LINE_DOCKER_PULL_POLICY, ASSEMBLY_LINE_DOCKER_COMMAND_TIMEOUT_MS
DaytonaDAYTONA_API_KEYOptional DAYTONA_API_URL, DAYTONA_TARGET, ASSEMBLY_LINE_DAYTONA_CREATE_TIMEOUT_SECONDS, ASSEMBLY_LINE_DAYTONA_LIFECYCLE_TIMEOUT_SECONDS, ASSEMBLY_LINE_DAYTONA_AUTO_STOP_MINUTES, ASSEMBLY_LINE_DAYTONA_AUTO_ARCHIVE_MINUTES, ASSEMBLY_LINE_DAYTONA_AUTO_DELETE_MINUTES, ASSEMBLY_LINE_DAYTONA_EPHEMERAL, ASSEMBLY_LINE_DAYTONA_NETWORK_BLOCK_ALL, ASSEMBLY_LINE_DAYTONA_NETWORK_ALLOW_LIST, ASSEMBLY_LINE_DAYTONA_DOMAIN_ALLOW_LIST
E2BE2B_API_KEYOptional E2B_TEMPLATE, ASSEMBLY_LINE_E2B_TIMEOUT_MS, ASSEMBLY_LINE_E2B_RETAIN_TIMEOUT_MS, ASSEMBLY_LINE_E2B_REQUEST_TIMEOUT_MS, ASSEMBLY_LINE_E2B_PAUSE_KEEP_MEMORY, ASSEMBLY_LINE_E2B_ALLOW_INTERNET_ACCESS
ModalMODAL_TOKEN_ID, MODAL_TOKEN_SECRETOptional MODAL_APP_NAME, ASSEMBLY_LINE_MODAL_TIMEOUT_MS, ASSEMBLY_LINE_MODAL_WAIT_READY

Provider snapshots are opt-in through the Assembly Line sandbox snapshot policy. Docker reports snapshots as unsupported. Daytona and E2B expose snapshot creation only when the installed provider SDK exposes it; Modal uses its filesystem snapshot image API. Normal production persistence remains Assembly Line state/blob sync.

Live sandbox smoke is opt-in:

pnpm smoke:sandbox -- --provider=docker
pnpm smoke:sandbox -- --provider=daytona
pnpm smoke:sandbox -- --provider=e2b
pnpm smoke:sandbox -- --provider=modal

Docker smoke runs when Docker is available. Hosted smoke skips cleanly when disposable provider credentials are missing. Smoke evidence is written locally under docs/internal/smoke/ (gitignored) and records provider, lifecycle result, safe file hashes, and snapshot status without secrets.

Deploy parity checks are also available without hosted-provider usage:

pnpm smoke:deploy:docker
pnpm smoke:deploy:fly
pnpm smoke:deploy:fly:live

The Docker check performs a real local image build, container recreation, remote command, and persistent-volume lifecycle. The Fly check gives the generated fly.toml to the installed flyctl local parser and verifies the deploy, volume, Machine, and SSH flags used by the publisher. It uses no valid Fly credential and cannot create provider resources. The explicit :live variant creates one ephemeral Fly app and volume, tests a real deploy, HTTP health, secret sync, SSH, redeploy persistence, and publisher-owned teardown, then verifies the app is absent. Hosted Fly and Modal smoke require credentials and may incur provider usage.

Blob Storage

Production blob storage is S3-compatible. R2 remains first-class through the R2 wrapper, but the runtime contract is the same for R2, AWS S3, and MinIO-style endpoints.

import { defineGateway } from "@assemblyline-agents/core";
import { s3Blob, r2Blob, minioBlob } from "@assemblyline-agents/s3";

export default defineGateway({
blob: r2Blob()
// or blob: s3Blob()
// or blob: minioBlob()
});

Generic S3 env:

  • S3_BUCKET
  • S3_REGION
  • S3_ACCESS_KEY_ID
  • S3_SECRET_ACCESS_KEY
  • optional S3_ENDPOINT
  • optional S3_FORCE_PATH_STYLE
  • optional S3_PREFIX
  • optional S3_PUBLIC_BASE_URL

R2 env:

  • R2_ACCOUNT_ID
  • R2_BUCKET
  • R2_ACCESS_KEY_ID
  • R2_SECRET_ACCESS_KEY
  • optional R2_PREFIX
  • optional R2_PUBLIC_BASE_URL

@assemblyline-agents/r2 still exports r2Adapter(), R2BlobAdapter, and InMemoryR2Bucket for existing imports.

S3_PUBLIC_BASE_URL and R2_PUBLIC_BASE_URL do not make every blob public. Blob writes are private by default; adapters return public HTTP URLs only when the write explicitly uses { visibility: "public" }.

Database

Assembly Line stays opinionated here: Postgres is the only production durable state plane in this phase. That keeps runs, messages, tool traces, schedules, dynamic connections, durable skills, idempotency, and migrations on one auditable database contract.

SQLite is not included because it would create a second production state shape just as deploy targets and channels are expanding. File-backed state remains for local dev/demo/test, not hosted production: it is single-process by design (its idempotency reservations live in process memory, so two hosts sharing one state file cannot coordinate leases or claims). Its writes are crash-safe — temp file, fsync, then atomic rename — and an unreadable state file is backed up to <path>.corrupt-<timestamp> and replaced with a fresh state instead of crashing the host, but multi-replica guarantees always require Postgres.

Connection grant and authorization-session stores follow the same production rule. Postgres implements those stores directly. File-backed connection credential stores are for local development or deliberately small deployments; production Node hosts using them must set ASSEMBLY_LINE_CONNECTION_STORE_SECRET or ASSEMBLY_LINE_SECRET to a stable secret of at least 32 characters. The known local development fallback is rejected outside devMode: true.

import { defineGateway } from "@assemblyline-agents/core";
import {
neonPostgres,
railwayPostgres,
supabasePostgres,
localPostgres,
postgresAdapter
} from "@assemblyline-agents/postgres";

export default defineGateway({
state: neonPostgres()
// or state: railwayPostgres()
// or state: supabasePostgres()
// or state: localPostgres()
// or state: postgresAdapter({ provider: "custom" })
});

Default env:

  • DATABASE_URL
  • optional ASSEMBLY_LINE_POSTGRES_CONNECTION_ENV
  • optional ASSEMBLY_LINE_POSTGRES_SSL_REJECT_UNAUTHORIZED (defaults to true; set false for self-signed/proxied certs)

Neon, Railway, Supabase, local Postgres, and custom Postgres all run the same Assembly Line migrations and schema. On a Railway deploy, railwayPostgres() uses the Railway CLI to reuse the configured database service or provision a real Postgres service, then sets the application service's DATABASE_URL to a private Railway reference variable before publishing. Its defaults are { databaseService: "Postgres", provision: true }; set provision: false to select a named pre-existing service instead. Automatic creation uses Railway's default Postgres service name. Railway's official Postgres image uses a generated certificate, so this preset keeps TLS enabled but defaults sslRejectUnauthorized to false. For Supabase, copy a direct connection string for a long-lived IPv6-capable host, or a session-pooler connection string when the host requires IPv4. Store either one as DATABASE_URL.

Observability

Telemetry is not a gateway adapter — it lives in agent/instrumentation.ts. @assemblyline-agents/otlp provides an OTLP/HTTP GenAI telemetry sink you wire in the setup callback; see Customizing Agents → Observability for the setup, capture-detail (captureContent) options, and the Langfuse recipe.