Open source · Self-hosted
Everything an agent needs, except the model.
Memory, knowledge, permissions, orchestration, evaluations and traces in one open-source server you run yourself. The model comes from the provider you choose, hosted or local.
docker compose up -dwith the quick start's Compose file: PostgreSQL, Ollama and the server, offline.
# 1. create the agentsoat create-agent \ --project-id "$PROJECT_ID" \ --ai-provider-id "$PROVIDER_ID" \ --name support-bot \ --instructions "You are a helpful support assistant."# 2. open a sessionsoat create-session \ --agent-id "$AGENT_ID" \ --name user-chat-42# 3. add the messagesoat add-session-message \ --session-id "$SESSION_ID" \ --message "Hello!"# 4. generate the answersoat generate-session-response \ --session-id "$SESSION_ID" \ --wait true# the reply, plus a trace_id recording every tool call and token
- Apache 2.0
- licensed, nothing withheld
- 1 process
- Node.js on PostgreSQL + pgvector
- 4 surfaces
- REST, MCP, CLI, SDK from one OpenAPI document
- v0.77.0
- latest release, pre-1.0
When to use SOAT
Reach for SOAT when the agent has to be trusted with something.
A single model call needs no infrastructure. SOAT earns its place the moment an agent has to remember, retrieve, coordinate, stay inside its permissions, or account for what it did. These are the jobs it is built for, the same list an agent reads at /agents.md, where each one names the call that does it.
- 01Sessions
Give an agent memory that survives the process
Sessions and conversations persist message history in PostgreSQL.
- 02Documents
Ground an agent in your own documents
Ingest files into chunked, embedded documents and search them with pgvector.
- 03Orchestrations
Run multi-step work deterministically instead of hoping one prompt covers it
Orchestrations are DAGs of agent, tool, and human nodes; workflows are state machines for long-running work.
- 04IAM
Bound what an agent is allowed to do
IAM policies gate every action, API keys scope to one project, guardrails screen input and output, and quotas cap spend.
- 05Approvals
Put a human in the loop without stopping the run
Approval nodes and exceptions pause a run, record who decided what, and resume from the same point.
- 06Traces
Prove after the fact what an agent did and what it cost
Every generation writes a trace with each tool call, model response, and token count, alongside an append-only audit log.
- 07Agents
Change an agent in production without guessing whether it got worse
Agent versions are append-only; a canary release splits traffic, and promotion is gated on a passing eval run.
- 08MCP
Expose your own backend to an MCP client (Claude, Cursor, VS Code)
Every REST operation is also an MCP tool, behind the same permission engine, with OAuth 2.1 discovery and Dynamic Client Registration.
- 09Formations
Stand up a whole agent stack reproducibly
Agent Formations declare providers, tools, agents, orchestrations, and webhooks in one template, resolve the dependency graph, and apply it.
How a call flows
Every caller reaches the same logic through the same permissions.
SOAT is open-source infrastructure for production-ready AI agents. You bring the product; SOAT handles the layer underneath it.
The REST API and the MCP endpoint are one Node.js process calling the same business logic through the same permission engine, so a resource created on one surface is already visible on the others. The server and its PostgreSQL database are the whole stack. Each module below links to its documentation.
Nothing else to run:a message queuea vector databasean auth servera trace collectora scheduler
Callers
State
- rows and files
- embeddings
- message history
- traces and audit log
Client surfaces
One backend. Four ways to call it.
The CLI, the SDK and the MCP tool surface are generated from the same OpenAPI documents the REST API is described by, so an operation that exists on one surface exists on all four. Pick the one that fits where your code runs. This is the same call, four times.
curl -X POST http://localhost:5047/api/v1/agents \
-H "Authorization: Bearer sk_..." \
-H "Content-Type: application/json" \
-d '{
"project_id": "proj_01HXYZ",
"ai_provider_id": "aip_01HXYZ",
"name": "support-bot",
"instructions": "You are a helpful support assistant."
}'
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create-agent",
"arguments": {
"project_id": "proj_01HXYZ",
"ai_provider_id": "aip_01HXYZ",
"name": "support-bot",
"instructions": "You are a helpful support assistant."
}
}
}
soat create-agent \
--project-id proj_01HXYZ \
--ai-provider-id aip_01HXYZ \
--name support-bot \
--instructions "You are a helpful support assistant."
import { SoatClient } from '@soat/sdk';
const soat = new SoatClient({
baseUrl: 'http://localhost:5047',
token: 'sk_...',
});
const { data: agent } = await soat.agents.createAgent({
body: {
project_id: 'proj_01HXYZ',
ai_provider_id: 'aip_01HXYZ',
name: 'support-bot',
instructions: 'You are a helpful support assistant.',
},
});
- Authentication
- one sk_ key or user JWT
- Permission
- agents:CreateAgent
- Data
- one PostgreSQL database
- Contract
- one OpenAPI document
Agent formations
Deploy a whole agent stack from one template.
Formations are the declarative layer. Describe the stack once, preview the plan, and SOAT creates or updates every dependent resource in the right order, with the same permissions and the same traceable operations as a hand-made call. Formations docs.
resources:
Provider:
type: ai_provider
properties:
name: openai
provider: openai
default_model: gpt-4o
Docs:
type: memory
properties:
name: product-docs
Lookup:
type: tool
properties:
name: order-lookup
type: http
execute:
url: https://api.example.com/orders/{order_id}
method: GET
Support:
type: agent
properties:
name: support-bot
ai_provider_id: { ref: Provider }
knowledge_config:
memory_ids: [{ ref: Docs }]
tool_bindings:
- tool_id: { ref: Lookup }
Hook:
type: webhook
depends_on: [Support]
properties:
name: session-events
url: https://example.com/hooks/soat
events: ['sessions.*']
plan-formation resolves the template into this graph.
- 01
Declare
soat validate-formationOne template, JSON or YAML: providers, memories, tools, agents, orchestrations and webhooks. Refs point at logical IDs, not at IDs that exist yet.
- 02
Resolve
soat plan-formationSOAT builds the dependency graph from refs and depends_on, rejects cycles, and provisions in topological rounds. Independent resources go in parallel.
- 03
Operate
soat list-formation-eventsEvery create, update and delete lands in an immutable event log with the resources it touched and the outputs it produced. A failed deploy rolls back.
How SOAT compares
13 alternatives, one rubric, gaps included.
Every solution is rated on the same 15 capability clusters from its public documentation, checked between 2026-08-14 and 2026-08-18. SOAT is rated like the rest, and its own gaps are on the table: Channels (absent), Code execution (absent), Skill learning (absent).
| Solution | Type | Runs | Agent runtime | Orchestration | Knowledge & memory | Tools & integration | Identity & governance | Observability | Data & secrets | Evaluation | Channels | Code execution | Human-in-the-loop | Multi-tenancy | Declarative deployment | Versioning & rollout | Skill learning | Native |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| SOAT | Infrastructure | self-hosted | Native | Native | Native | Native | Native | Native | Native | Native | Absent | Absent | Native | Native | Native | Native | Absent | 12/15 |
| Amazon Bedrock AgentCore | Managed platform | managed | Native | Native | Native | Native | Native | Native | Partial | Native | Absent | Native | Native | Partial | Native | Native | Absent | 11/15 |
| Claude Developer Platform | Managed platform | managed | Native | Partial | Partial | Native | Partial | Native | Native | Partial | Absent | Native | Native | Native | Partial | Partial | Partial | 7/15 |
| CrewAI | Framework | self-hosted / managed | Native | Native | Native | Native | Partial | Partial | Absent | Partial | Partial | Native | Native | Partial | Partial | Absent | Absent | 6/15 |
| DeepSeek Harness | Framework | self-hosted | Native | Partial | Via plugin | Native | Absent | Partial | Partial | Absent | Via plugin | Native | Native | Absent | Partial | Absent | Absent | 4/15 |
| Dify | Infrastructure | self-hosted / managed | Native | Native | Native | Native | Partial | Native | Native | Absent | Partial | Native | Native | Partial | Partial | Partial | Absent | 8/15 |
| Hermes Agent | Framework | self-hosted | Native | Partial | Native | Native | Absent | Partial | Absent | Partial | Native | Native | Native | Absent | Absent | Absent | Native | 7/15 |
| LangChain / LangGraph | Framework | self-hosted / managed | Native | Native | Native | Native | Partial | Partial | Absent | Partial | Via plugin | Via plugin | Native | Partial | Partial | Partial | Via plugin | 5/15 |
| Letta | Infrastructure | self-hosted / managed | Native | Native | Native | Native | Partial | Partial | Absent | Absent | Native | Partial | Native | Partial | Via plugin | Via plugin | Native | 7/15 |
| Microsoft Agent Framework | Framework | self-hosted / managed | Native | Native | Partial | Native | Partial | Native | Absent | Native | Partial | Partial | Native | Absent | Partial | Absent | Absent | 6/15 |
| Microsoft Foundry Agent Service | Managed platform | managed | Native | Native | Native | Native | Native | Native | Partial | Native | Native | Native | Native | Partial | Native | Native | Partial | 12/15 |
| OpenAI Agents platform | Managed platform | managed | Native | Native | Native | Native | Partial | Native | Partial | Partial | Partial | Native | Native | Native | Absent | Partial | Absent | 8/15 |
| OpenClaw | Framework | self-hosted | Native | Partial | Native | Native | Partial | Absent | Absent | Absent | Native | Native | Native | Absent | Absent | Absent | Partial | 6/15 |
| Vertex AI Agent Builder | Managed platform | managed | Native | Native | Native | Native | Partial | Native | Partial | Native | Partial | Native | Partial | Partial | Partial | Native | Absent | 8/15 |
Built for agents
Everything on this site is readable by a machine.
Every page is server-rendered with its full text in the HTML and has a Markdown twin one URL away. The REST surface is one OpenAPI description and errors are a catalog of stable codes, so a client can be generated without scraping a page.
| path | type | what an agent gets |
|---|---|---|
| /agents.md | text/markdown | Instructions for an agent: which jobs SOAT is the right tool for, which it is not, how to authenticate and call it, and how to get access. |
| /llms.txt | text/plain | Index of every documentation page, with a one-line summary and a link to each Markdown twin. |
| /llms-full.txt | text/plain | The whole prose documentation corpus in one file, ready to be chunked and embedded. |
| /openapi.json | application/json | Every REST operation of the SOAT API in a single OpenAPI 3.0 description — paths, schemas, and security schemes. |
| /openapi.yaml | application/yaml | The same merged OpenAPI description in YAML, also served at /api/openapi.yaml. |
| /errors.json | application/json | Catalog of every error code the API can return, with its HTTP status and what to do about it. |
| /docs/openapi-specs | text/html | One YAML spec per module under /openapi/<module>.yaml, for tools that prefer a narrower surface. |
| /sitemap.xml | application/xml | Every canonical page with its last-modified date, so a crawler can fetch only what changed. |
| /robots.txt | text/plain | Crawl policy: everything is allowed, plus the sitemap link. |
Send Accept: text/markdown to any documentation URL, or append .md, as in /docs/introduction.md. A dead URL answers a real 404 with a Markdown recovery map.
The four layers of an agent system
Harness first. Loop second. Graph last. Then the ratchet.
An agent system decomposes into four layers, and the investment order is not equal. SOAT is built around that order: every module owns one layer, so when a layer is the one failing you know which part of the platform to reach for. Read the framing.
Harness
What can this agent reach, and what is it forbidden?
Most failures live here, and so do the cheapest wins. Tools are first-class resources, knowledge and memory are scoped, and every permission is a policy document.
Loop
What proves it did the job, and when does it stop?
Output schemas, step limits and stop conditions bound the run. Guardrails classify every tool call before it executes, quotas fail closed, and each generation writes a trace.
Graph
What is allowed to happen next?
DAG orchestrations with parallel rounds, state-machine workflows for long-running work, and triggers on a cron, a webhook or an event. Built last, because it is needed least often.
Ratchetgoverns change itself
How does the system change, and what proves the change was an improvement?
Agent versions are append-only, a canary splits traffic, and promotion waits for a passing eval run against that canary. The platform owns the verdict; a human owns the judgment.
Getting access
No signup. No sales call. No waitlist.
SOAT is Apache-2.0 software you run yourself. A local deployment is the same software as a production one: the sandbox, the free tier and the product are one thing. Keys are minted by an API call, which matters because an agent cannot fill in a contact form.
Run it locallyNothing to sign up for
SOAT is Apache-2.0 licensed and self-hosted. There is no account to create, no key to request, no trial to start, and no quota you have to ask anyone to raise.
Run the stack
Copy the Compose file from the quick start and run docker compose up -d. It brings up PostgreSQL with pgvector, a local Ollama for models, and the SOAT server on port 5047 — so the whole platform runs offline, with no third-party credential.
Get the first credential
POST /api/v1/users/bootstrap creates the first admin. It is open only until that admin exists, then closed for good, so the same call cannot be replayed against a running deployment.
Issue your own API key
POST /api/v1/api-keys (or soat create-api-key) mints a project-scoped sk_… key with exactly the actions of the policy you attach. Keys are self-serve and rotatable — POST /api/v1/api-keys/{api_key_id}/rotate.
The sandbox is the same software
There is no separate sandbox tier to request: a local instance is the product, so throwaway projects, seeded data, and destructive tests all run against your own deployment. Delete the volumes to reset.
Stop rebuilding agent infrastructure.
Self-host SOAT and ship agents that can reach what they need, prove they did the job, and improve on evidence.