Agents
Creating an agent and publishing the versions a session binds to.
An agent is a model, a prompt, and the things the model is allowed to reach. You publish it as a version, and a session binds to that version for its whole life. Publishing a new one later does not change a session already running.
These routes need a workspace credential, so they live on SubakoClient and not on SubakoSessionClient.
Creating one
const agent = await subako.agents.create({ name: "support" });
That gives you an agent with no versions yet. Nothing can run on it until you publish one.
await subako.agents.rename(agent.id, { name: "support-triage" });
await subako.agents.delete(agent.id);
const page = await subako.agents.list({ limit: 50 });
Publishing a version
The config is the version. You send the whole document, and what comes back is immutable.
const version = await subako.agents.publishVersion(agent.id, {
model: {
format: "anthropic",
model: "claude-sonnet-5",
max_tokens: 8192,
},
system_prompt: "You help people file support tickets.",
});
model picks the wire format and carries that format’s settings. There are two:
// Anthropic
{ format: "anthropic", model: "claude-sonnet-5", max_tokens: 8192, thinking: { budget_tokens: 4096 } }
// OpenAI Responses
{ format: "openai_responses", model: "gpt-5", max_tokens: 8192, context_window: 200_000, reasoning_effort: "medium" }
Which models you can name depends on the providers the workspace has. subako.modelProviders.list() tells you.
To see what has been published:
const versions = await subako.agents.listVersions(agent.id, { limit: 20 });
What the config grants
Beyond the model and the prompt, the config names what the agent may reach. Each grant gets a name that the model sees the thing under.
Skills
skills: [
{ name: "refunds", skill_id: refund.skill_id, version: { type: "latest" } },
{ name: "policy", skill_id: policy.skill_id, version: { type: "pinned", number: 3 } },
]
latest is resolved when each session is created, so a session started tomorrow may see a newer bundle. pinned never moves. See Skills.
MCP servers
mcp: [
{
name: "tickets",
url: "https://mcp.example.com/tickets",
default_policy: "require_approval",
tools: [{ name: "search_tickets", policy: "allow" }],
},
]
The broker serves the server at mcp:{name}. default_policy is allow, require_approval or deny, and it covers any tool not named in tools — including a tool the server adds after this version was published. A require_approval call shows up in the session log as an approval_requested event and the run waits; see Reading the log.
Credentials for these do not go in the config. They live in a vault, and the broker attaches them — see Vaults.
Sandboxes
sandboxes: [
{
name: "build",
environment: { type: "platform", release: "2026" },
default_policy: "allow",
},
]
Each grant is a Linux instance the session owns, served at sandbox:{name} with an exec tool. Sandboxes covers reading them back.
Browser origins
This only matters if a browser talks to Subako directly. An agent answers no cross-origin request until you say which origins are allowed, so a page using SubakoSessionClient will fail its preflight until you do. A server-side job never sends an Origin and never needs this.
await subako.agents.setSecurity(agent.id, {
allowed_origins: ["https://app.example.com"],
});
const security = await subako.agents.getSecurity(agent.id);
This is the piece people miss when a session works from their backend and not from their page.
Starting a session on it
const created = await subako.sessions.create({
agent_id: agent.id,
display_name: "support",
});
The session binds the agent’s current version at that moment. Quickstart shows what to do with the token that comes back.