subs is an agent harness for the cloud. It runs an unprivileged agent loop and uses MCP servers for executing tools. Use it locally, remotely and with your team. You can customize everything.
翻譯準備中
正在載入完整 README。
檢視完整 README ↗Pre-1.0: APIs and the wire protocol can change between releases.
subs is an agent harness for the cloud.
It runs an unprivileged agent loop with no system access. It uses MCP servers for tools. It runs locally or as a client and a server.
Declare your agents in a config file. To customize the loop, point an agent at an HTTP endpoint and answer a webhook.
subs handles durability, retries, timeouts, MCP connection management, session state, session branching, AG-UI, Slack connection, LLM calls, subagents, interrupts and more.
To turn a sandbox into an MCP server, see mcpd.
curl -fsSL https://subs.dev/cli.sh | bash
The CLI is also the engine.
Create a subs.toml.
name = "example"
[llm.openrouter]
type = "openrouter"
[agent.teammate]
llm = "openrouter"
model = "deepseek/deepseek-v4-flash-0731"
system = "You are a helpful teammate."
Set your provider key and talk to the agent.
export OPENROUTER_API_KEY=sk-or-...
subs chat teammate -c subs.toml
Add a [serve] section and a [remote] that points at it.
[serve]
port = 9999
auth = false
[remote]
url = "http://localhost:9999"
Start the server.
subs serve -c subs.toml
In another terminal, the same chat command now talks to it.
subs chat teammate -c subs.toml
Point [remote] at the hosted engine instead of your own.
[remote]
url = "https://api.substructure.ai"
Create the project from the file, then upload your LLM key.
subs apply
subs auth llm.openrouter
The same chat command now runs the turn on the hosted engine.
subs chat teammate -c subs.toml
Say which agent takes a DM and which one answers a mention.
[slack]
dm = "teammate"
mentions = "teammate"
Apply the file again, then connect your workspace.
subs apply
subs slack connect
Mention the bot in a channel and it answers in the thread.
Declare the server and give it to an agent. Every user of the agent shares one credential.
[mcp.sentry]
url = "https://mcp.sentry.dev/mcp"
[agent.teammate]
llm = "openrouter"
model = "deepseek/deepseek-v4-flash-0731"
system = "You are a helpful teammate."
mcp = ["mcp.sentry"]
Authorize the connection.
subs auth mcp.sentry
Set credential = "user" and each user connects their own account. A
user-scoped connection works only in a one-on-one chat between the agent and
that user.
[mcp.linear]
url = "https://mcp.linear.app/mcp"
credential = "user"
[agent.personal]
llm = "openrouter"
model = "deepseek/deepseek-v4-flash-0731"
system = "Help me with my Linear issues."
mcp = ["mcp.linear"]
[slack]
dm = "personal"
mentions = "teammate"
Point an agent at a URL and the engine sends every decision for that agent to your code. This gives you full control of the loop, including how the agent behaves in Slack.
[agent.teammate]
llm = "openrouter"
model = "deepseek/deepseek-v4-flash-0731"
system = "You are a helpful teammate."
mcp = ["mcp.sentry"]
worker = "https://example.com/agent"
Your endpoint reads the engine's proposal and returns it, changing only the steps you care about. There is no SDK to install.
import { serve } from "@hono/node-server";
import { Hono } from "hono";
import type { DecisionRequest, DecisionResponse } from "./protocol.ts";
function decide({ trigger, proposed }: DecisionRequest): DecisionResponse {
if (trigger.type === "session.start") {
return {
agent: {
...proposed.agent,
tools: [{ name: "current_time", description: "Get the current time" }]
}
};
}
// Run our tool when the model calls it.
if (trigger.type === "tool.execute" && trigger.name === "current_time") {
return { actions: [{ type: "tool.result", result: new Date().toISOString() }] };
}
// Accept the engine's proposal for everything else.
return proposed;
}
const app = new Hono();
app.post("/", async (c) => c.json(decide(await c.req.json())));
serve({ fetch: app.fetch, port: 4444 });
Only the agents that name a worker use one. The rest stay with the engine, in the same project and the same file.
Full walkthrough in the quick start. Docs: Workers, Connectors, Slack, Local development
Mention the bot or DM it. The thread is the session. Route different channels to different agents.
Docs: Slack
subs chat holds one session open, streams the reply as it is written, and
turns an approval prompt into a picker. The session is the same kind a Slack
thread is.
Docs: Chat
Examples: no-code-chat
At each step the engine tells your code what it plans to do next. Accept the plan or do something else. A working agent is a few lines.
Docs: How it works
Your agent is an HTTP endpoint. Generate typed bindings from the published JSON schema.
Docs: Typed bindings
Examples: Go, Python, TypeScript, Elixir
以上為 README 的開頭部分。其餘內容請閱讀原文。 檢視完整 README ↗