gateway
A gateway block runs a managed subprocess that bridges Squadron to an external system — a Discord channel, a Slack workspace, a Microsoft Teams chat, a custom web dashboard, anything you build against the Gateway SDK.
The gateway subscribes to live human_input_requested / human_input_resolved events from Squadron and surfaces them in its target system; user actions in that system flow back to Squadron through the same record store. From the agent’s perspective, an answer in Discord is indistinguishable from one typed into the Command Center Inbox.
A gateway can also receive mission-lifecycle notifications (mission_completed / mission_failed / mission_stopped) when a mission opts in via a notification block — a one-way post, separate from the interactive human-input flow.
Squadron supports at most one gateway block per instance.
Minimal Example — Discord
variable "discord_bot_token" {
secret = true
}
variable "discord_channel_id" {}
gateway "discord" {
source = "github.com/mlund01/squadron-gateway-discord"
version = "v0.0.1"
settings = {
bot_token = vars.discord_bot_token
channel_id = vars.discord_channel_id
checkpoint_path = "${path.cwd}/.squadron/discord-gateway.json"
}
}Restart Squadron and the next builtins.human.ask call will appear in the configured Discord channel as a message with quick-reply buttons (or a multi-select dropdown when multi_select = true on the tool call).
Posting from an agent — builtins.gateway.post
When a gateway is configured, agents gain a built-in tool, builtins.gateway.post, for posting a message to the gateway’s channel. Use it to send a heads-up, status update, or summary to the team mid-mission.
agent "announcer" {
model = models.anthropic.claude_sonnet_4
tools = [builtins.gateway.post]
}The gateway owns the message contract. Each gateway advertises (via the SDK’s MessageToolSpec) the tool’s description and a JSON Schema for its parameters, so the LLM sees exactly the rich-message shape that gateway supports — squadron just forwards the agent’s payload through. See your gateway’s README for the exact fields it accepts.
A gateway that advertises no spec falls back to a simple { message, channel } shape. The tool is one-way (the agent doesn’t wait for a reply); for interactive prompts use builtins.human.ask instead.
Attachments are local files. Independent of the gateway-owned fields, squadron adds an attachments parameter (present only when the mission has memory or a scratchpad). It takes a list of { slot, path } objects referencing squadron’s own files — for example { "slot": "scratchpad", "path": "report.pdf" }. Squadron reads each file and ships the bytes to the gateway to upload. Attachments are never URLs the model picks, so there is no outbound-fetch (SSRF) surface; the per-file cap is 25 MB.
Tip: rich payloads (Block Kit
blocks, Discordembeds) are large nested JSON. Smaller models sometimes drop the nested field and post text only. If an agent needs to emit rich layouts reliably, give it a capable model.
builtins.gateway.post is only a valid tool reference when a gateway block is present — squadron verify rejects it otherwise.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
name (label) | string | yes | Used in logs and the install path (.squadron/gateways/<platform>/<name>/<version>/gateway). |
source | string | yes (unless version = "local") | GitHub source path. Squadron downloads the matching release archive on first load. |
version | string | yes | Release tag (e.g. v0.0.1) or local to use a developer-built binary. |
settings | map | no | Free-form key/value map passed to the gateway’s Configure. Each gateway documents its own keys. |
Lifecycle
squadron verifypre-flights the install (download + checksum verify) and exits non-zero if the gateway can’t be installed — same fail-loudly behavior as plugins.squadron engagere-runs the install pre-flight before the daemon signals ready, so a broken gateway fails theengagecommand instead of leaving you with a half-running daemon.- Once installed, Squadron launches the gateway as a managed subprocess at startup (same install model as native plugins).
- A watchdog polls the subprocess and automatically restarts on crash with exponential backoff (capped at 30s).
- The SDK includes orphan prevention — if the parent Squadron process dies, the gateway exits on the next watchdog tick rather than lingering.
- On reconnect, the gateway uses a checkpoint (timestamp of the last event it processed) to catch up via
ListHumanInputs(Since=…)so no questions are dropped during a transient disconnect.
Local Development
Use version = "local" to skip the GitHub download and use a binary you’ve placed at the cache path:
gateway "discord" {
version = "local"
settings = { ... }
}Build and install:
go build -o gateway .
mkdir -p ~/.squadron/gateways/darwin-arm64/discord/local
mv gateway ~/.squadron/gateways/darwin-arm64/discord/local/gatewayAdjust the platform path to match runtime.GOOS-runtime.GOARCH.
Available Gateways
squadron-gateway-discord— bridges questions to a Discord channel.
Building Your Own
Gateways are Go programs built against squadron-gateway-sdk. See the SDK README for the Gateway interface, hello-world template, catch-up patterns, and the release-archive shape Squadron expects when distributing your gateway.