Skip to main content
← Back to list
01Issue
FeatureOpenSwamp CLIPublic
AssigneesNone

Relationships

#2326 Expose Swamp as a REST/OpenAPI endpoint (for GPT Actions and other REST clients)

Opened by usefulish · 9/21/2026

Problem Statement

swamp serve exposes Swamp's automation surface as a WebSocket protocol (workflow.search / workflow.run / workflow.run.search / … streamed as event + done/error frames). That is great for native clients, but it is a poor fit for the dominant user-facing integration pattern: REST/OpenAPI.

The clearest example is a ChatGPT GPT Action, which can only consume an OpenAPI 3.0 document over HTTPS. A WebSocket-only server is unreachable from a GPT Action, so Swamp cannot be wired into ChatGPT (or any other REST-first tool: Zapier, Retool, a plain fetch) without every integrator hand-rolling a translation adapter.

This is the companion to #2323 (promote CodeBuddy/WorkBuddy to first-class clients): even first-class clients would benefit from a REST surface, and the user-facing ChatGPT integration specifically needs REST, not the full CLI.

Evidence: a working adapter already exists

To prove the gap is bridgeable with what Swamp ships today, I built packages/swamp-chatgpt-gateway in automation-factory (https://github.com/usefulish/automation-factory). It is a thin Deno HTTP server that:

  • Opens a short-lived WebSocket to swamp serve per request, forwarding the caller's bearer token as the bearer.<token> subprotocol (auth is delegated entirely to Swamp — the gateway holds no credentials of its own).
  • Translates Swamp's frames into three REST endpoints:
    • GET /v1/workflows → workflow.search
    • POST /v1/workflows/{name}/runs → workflow.run (synchronous; returns runId + event log)
    • GET /v1/runs/{id} → workflow.run.search
  • Relies on Swamp's grant model for scoping: a token granted only read/run on workflow:promo-model-checker returns only that workflow from the search endpoint, and a run of any other workflow is denied by Swamp with Access denied … does not have 'run' on workflow:…. "List my approved workflows" and "run only what I'm allowed to" come for free.

Verified end-to-end against a real swamp serve --auth-mode token with a grant-scoped token:

  • GET /v1/workflows → [promo-model-checker] (the mintlify-docs workflow is correctly hidden — no read grant).
  • POST /v1/workflows/promo-model-checker/runs → 200, runId + completed event stream (status: completed).
  • POST /v1/workflows/@usefulish/mintlify-docs/runs → 502 carrying Swamp's Access denied … does not have 'run' on workflow:@usefulish/mintlify-docs.

Protocol gotcha worth knowing for anyone building this

Non-run calls (workflow.search, workflow.run.search, workflow.history.get) return a single response payload frame and no terminal done frame — only workflow.run streams events and then done. A REST adapter must resolve on the response frame for those calls, not wait for done. (This cost one debugging cycle; documenting it so the next integrator doesn't repeat it.)

Proposed solution

Ship a first-class REST/OpenAPI surface for Swamp rather than leaving each integrator to reimplement the WS→REST translation. Options, roughly in order of preference:

  1. A swamp serve --protocol rest (or a --rest-port) mode that exposes the same operations over HTTPS with an OpenAPI document served at /openapi.json, reusing the existing auth (bearer token / OAuth) and grant scoping. This keeps a single source of truth for authorization.
  2. A reference REST gateway binary (swamp gateway / swamp serve --rest-adapter) maintained in-repo, so GPT Actions and other REST clients have a blessed, version-matched adapter instead of N third-party ones.
  3. At minimum, publish a canonical OpenAPI document for the operations Swamp already supports, plus a note that serve is WebSocket and how to bridge it — so the integration pattern is documented, not discovered.

The three-endpoint subset above (enumerate approved / run / fetch result) is the minimal useful surface for a user-facing assistant; model methods, data, access admin, and approve/reject can follow once the transport exists.

Why now

User-facing AI integrations (ChatGPT GPT Actions, agent harnesses) are the most likely first contact a new Swamp user has with the automation surface, and they are uniformly REST/OpenAPI. Today that audience is blocked at the transport layer. The evidence adapter shows the bridge is small and that Swamp's grant model already does the hard part (authorization).

02Bog Flow
◉OPEN○TRIAGED○IN PROGRESS○SHIPPED

Open

9/21/2026, 7:17:03 PM

No activity in this phase yet.

03Sludge Pulse
Editable. Press Enter to edit.

usefulish commented 9/21/2026, 8:54:16 PM

Related real-world evidence (2026-09-21): we built a REST/OpenAPI adapter in front of swamp serve (packages/swamp-chatgpt-gateway) so a ChatGPT GPT Action can call Swamp. Two concrete findings that argue for a native REST/OpenAPI surface:

  1. swamp serve is WebSocket-only. The token must be passed via ?token=[REDACTED-SECRET-1]Authorization: Bearer), NOT the bearer.<token> WebSocket subprotocol — Swamp secrets can contain + / =, which are outside the RFC 6455 subprotocol charset range, so runtimes like Deno reject new WebSocket(url, ["bearer.<token>"]) with "Invalid protocol value". A native HTTP surface removes this class of bug entirely.
  2. Every REST client today has to reimplement the WS protocol plus that token workaround. Even a generated/stabled OpenAPI spec emitted by swamp serve (without a built-in HTTP server) would let clients generate SDKs and drop the custom adapter.

Our adapter is committed as a compatibility shim. A welcome first step is swamp serve emitting a stable OpenAPI spec; a full HTTP surface mapping workflow.search / workflow.run / workflow.run.search would be ideal.

Sign in to post a ripple.