docs: add mcp and skill session config (#106)

This commit is contained in:
NathanFlurry 2026-02-09 10:13:25 +00:00
parent d236edf35c
commit 4c8d93e077
No known key found for this signature in database
GPG key ID: 6A5F43A4F3241BCA
95 changed files with 10014 additions and 1342 deletions

278
docs/agent-sessions.mdx Normal file
View file

@ -0,0 +1,278 @@
---
title: "Agent Sessions"
description: "Create sessions and send messages to agents."
sidebarTitle: "Sessions"
icon: "comments"
---
Sessions are the unit of interaction with an agent. You create one session per task, then send messages and stream events.
## Session Options
`POST /v1/sessions/{sessionId}` accepts the following fields:
- `agent` (required): `claude`, `codex`, `opencode`, `amp`, or `mock`
- `agentMode`: agent mode string (for example, `build`, `plan`)
- `permissionMode`: permission mode string (`default`, `plan`, `bypass`, etc.)
- `model`: model override (agent-specific)
- `variant`: model variant (agent-specific)
- `agentVersion`: agent version override
- `mcp`: MCP server config map (see `MCP`)
- `skills`: skill path config (see `Skills`)
## Create A Session
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.createSession("build-session", {
agent: "codex",
agentMode: "build",
permissionMode: "default",
model: "gpt-4.1",
variant: "reasoning",
agentVersion: "latest",
});
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/sessions/build-session" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"agent": "codex",
"agentMode": "build",
"permissionMode": "default",
"model": "gpt-4.1",
"variant": "reasoning",
"agentVersion": "latest"
}'
```
</CodeGroup>
## Send A Message
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.postMessage("build-session", {
message: "Summarize the repository structure.",
});
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/sessions/build-session/messages" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"message":"Summarize the repository structure."}'
```
</CodeGroup>
## Stream A Turn
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
const response = await client.postMessageStream("build-session", {
message: "Explain the main entrypoints.",
});
const reader = response.body?.getReader();
if (reader) {
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
console.log(decoder.decode(value, { stream: true }));
}
}
```
```bash cURL
curl -N -X POST "http://127.0.0.1:2468/v1/sessions/build-session/messages/stream" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"message":"Explain the main entrypoints."}'
```
</CodeGroup>
## Fetch Events
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
const events = await client.getEvents("build-session", {
offset: 0,
limit: 50,
includeRaw: false,
});
console.log(events.events);
```
```bash cURL
curl -X GET "http://127.0.0.1:2468/v1/sessions/build-session/events?offset=0&limit=50" \
-H "Authorization: Bearer $SANDBOX_TOKEN"
```
</CodeGroup>
`GET /v1/sessions/{sessionId}/get-messages` is an alias for `events`.
## Stream Events (SSE)
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
for await (const event of client.streamEvents("build-session", { offset: 0 })) {
console.log(event.type, event.data);
}
```
```bash cURL
curl -N -X GET "http://127.0.0.1:2468/v1/sessions/build-session/events/sse?offset=0" \
-H "Authorization: Bearer $SANDBOX_TOKEN"
```
</CodeGroup>
## List Sessions
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
const sessions = await client.listSessions();
console.log(sessions.sessions);
```
```bash cURL
curl -X GET "http://127.0.0.1:2468/v1/sessions" \
-H "Authorization: Bearer $SANDBOX_TOKEN"
```
</CodeGroup>
## Reply To A Question
When the agent asks a question, reply with an array of answers. Each inner array is one multi-select response.
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.replyQuestion("build-session", "question-1", {
answers: [["yes"]],
});
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/sessions/build-session/questions/question-1/reply" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"answers":[["yes"]]}'
```
</CodeGroup>
## Reject A Question
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.rejectQuestion("build-session", "question-1");
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/sessions/build-session/questions/question-1/reject" \
-H "Authorization: Bearer $SANDBOX_TOKEN"
```
</CodeGroup>
## Reply To A Permission Request
Use `once`, `always`, or `reject`.
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.replyPermission("build-session", "permission-1", {
reply: "once",
});
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/sessions/build-session/permissions/permission-1/reply" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reply":"once"}'
```
</CodeGroup>
## Terminate A Session
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.terminateSession("build-session");
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/sessions/build-session/terminate" \
-H "Authorization: Bearer $SANDBOX_TOKEN"
```
</CodeGroup>

87
docs/attachments.mdx Normal file
View file

@ -0,0 +1,87 @@
---
title: "Attachments"
description: "Upload files into the sandbox and attach them to prompts."
sidebarTitle: "Attachments"
icon: "paperclip"
---
Use the filesystem API to upload files, then reference them as attachments when sending prompts.
<Steps>
<Step title="Upload a file">
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
import fs from "node:fs";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
const buffer = await fs.promises.readFile("./data.csv");
const upload = await client.writeFsFile(
{ path: "./uploads/data.csv", sessionId: "my-session" },
buffer,
);
console.log(upload.path);
```
```bash cURL
curl -X PUT "http://127.0.0.1:2468/v1/fs/file?path=./uploads/data.csv&sessionId=my-session" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
--data-binary @./data.csv
```
</CodeGroup>
The response returns the absolute path that you should use for attachments.
</Step>
<Step title="Attach the file in a prompt">
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.postMessage("my-session", {
message: "Please analyze the attached CSV.",
attachments: [
{
path: "/home/sandbox/uploads/data.csv",
mime: "text/csv",
filename: "data.csv",
},
],
});
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/sessions/my-session/messages" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "Please analyze the attached CSV.",
"attachments": [
{
"path": "/home/sandbox/uploads/data.csv",
"mime": "text/csv",
"filename": "data.csv"
}
]
}'
```
</CodeGroup>
</Step>
</Steps>
## Notes
- Use absolute paths from the upload response to avoid ambiguity.
- If `mime` is omitted, the server defaults to `application/octet-stream`.
- OpenCode receives file parts directly; other agents will see the attachment paths appended to the prompt.

View file

@ -2,7 +2,6 @@
title: "CLI Reference"
description: "Complete CLI reference for sandbox-agent."
sidebarTitle: "CLI"
icon: "terminal"
---
## Server
@ -250,6 +249,8 @@ sandbox-agent api sessions create <SESSION_ID> [OPTIONS]
| `-m, --model <MODEL>` | Model override |
| `-v, --variant <VARIANT>` | Model variant |
| `-A, --agent-version <VERSION>` | Agent version |
| `--mcp-config <PATH>` | JSON file with MCP server config (see `mcp` docs) |
| `--skill <PATH>` | Skill directory or `SKILL.md` path (repeatable) |
```bash
sandbox-agent api sessions create my-session \
@ -381,6 +382,132 @@ sandbox-agent api sessions reply-permission my-session perm1 --reply once
---
### Filesystem
#### List Entries
```bash
sandbox-agent api fs entries [OPTIONS]
```
| Option | Description |
|--------|-------------|
| `--path <PATH>` | Directory path (default: `.`) |
| `--session-id <SESSION_ID>` | Resolve relative paths from the session working directory |
```bash
sandbox-agent api fs entries --path ./workspace
```
#### Read File
`api fs read` writes raw bytes to stdout.
```bash
sandbox-agent api fs read <PATH> [OPTIONS]
```
| Option | Description |
|--------|-------------|
| `--session-id <SESSION_ID>` | Resolve relative paths from the session working directory |
```bash
sandbox-agent api fs read ./notes.txt > ./notes.txt
```
#### Write File
```bash
sandbox-agent api fs write <PATH> [OPTIONS]
```
| Option | Description |
|--------|-------------|
| `--content <TEXT>` | Write UTF-8 content |
| `--from-file <PATH>` | Read content from a local file |
| `--session-id <SESSION_ID>` | Resolve relative paths from the session working directory |
```bash
sandbox-agent api fs write ./hello.txt --content "hello"
sandbox-agent api fs write ./image.bin --from-file ./image.bin
```
#### Delete Entry
```bash
sandbox-agent api fs delete <PATH> [OPTIONS]
```
| Option | Description |
|--------|-------------|
| `--recursive` | Delete directories recursively |
| `--session-id <SESSION_ID>` | Resolve relative paths from the session working directory |
```bash
sandbox-agent api fs delete ./old.log
```
#### Create Directory
```bash
sandbox-agent api fs mkdir <PATH> [OPTIONS]
```
| Option | Description |
|--------|-------------|
| `--session-id <SESSION_ID>` | Resolve relative paths from the session working directory |
```bash
sandbox-agent api fs mkdir ./cache
```
#### Move/Rename
```bash
sandbox-agent api fs move <FROM> <TO> [OPTIONS]
```
| Option | Description |
|--------|-------------|
| `--overwrite` | Overwrite destination if it exists |
| `--session-id <SESSION_ID>` | Resolve relative paths from the session working directory |
```bash
sandbox-agent api fs move ./a.txt ./b.txt --overwrite
```
#### Stat
```bash
sandbox-agent api fs stat <PATH> [OPTIONS]
```
| Option | Description |
|--------|-------------|
| `--session-id <SESSION_ID>` | Resolve relative paths from the session working directory |
```bash
sandbox-agent api fs stat ./notes.txt
```
#### Upload Batch (tar)
```bash
sandbox-agent api fs upload-batch --tar <PATH> [OPTIONS]
```
| Option | Description |
|--------|-------------|
| `--tar <PATH>` | Tar archive to extract |
| `--path <PATH>` | Destination directory |
| `--session-id <SESSION_ID>` | Resolve relative paths from the session working directory |
```bash
sandbox-agent api fs upload-batch --tar ./skills.tar --path ./skills
```
---
## CLI to HTTP Mapping
| CLI Command | HTTP Endpoint |
@ -399,3 +526,11 @@ sandbox-agent api sessions reply-permission my-session perm1 --reply once
| `api sessions reply-question` | `POST /v1/sessions/{sessionId}/questions/{questionId}/reply` |
| `api sessions reject-question` | `POST /v1/sessions/{sessionId}/questions/{questionId}/reject` |
| `api sessions reply-permission` | `POST /v1/sessions/{sessionId}/permissions/{permissionId}/reply` |
| `api fs entries` | `GET /v1/fs/entries` |
| `api fs read` | `GET /v1/fs/file` |
| `api fs write` | `PUT /v1/fs/file` |
| `api fs delete` | `DELETE /v1/fs/entry` |
| `api fs mkdir` | `POST /v1/fs/mkdir` |
| `api fs move` | `POST /v1/fs/move` |
| `api fs stat` | `GET /v1/fs/stat` |
| `api fs upload-batch` | `POST /v1/fs/upload-batch` |

245
docs/custom-tools.mdx Normal file
View file

@ -0,0 +1,245 @@
---
title: "Custom Tools"
description: "Give agents custom tools inside the sandbox using MCP servers or skills."
sidebarTitle: "Custom Tools"
icon: "wrench"
---
There are two ways to give agents custom tools that run inside the sandbox:
| | MCP Server | Skill |
|---|---|---|
| **How it works** | Sandbox Agent spawns your MCP server process and routes tool calls to it via stdio | A markdown file that instructs the agent to run your script with `node` (or any command) |
| **Tool discovery** | Agent sees tools automatically via MCP protocol | Agent reads instructions from the skill file |
| **Best for** | Structured tools with typed inputs/outputs | Lightweight scripts with natural-language instructions |
| **Requires** | `@modelcontextprotocol/sdk` dependency | Just a markdown file and a script |
Both approaches execute code inside the sandbox, so your tools have full access to the sandbox filesystem, network, and installed system tools.
## Option A: Tools via MCP
<Steps>
<Step title="Write your MCP server">
Create an MCP server that exposes tools using `@modelcontextprotocol/sdk` with `StdioServerTransport`. This server will run inside the sandbox.
```ts src/mcp-server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "rand",
version: "1.0.0",
});
server.tool(
"random_number",
"Generate a random integer between min and max (inclusive)",
{
min: z.number().describe("Minimum value"),
max: z.number().describe("Maximum value"),
},
async ({ min, max }) => ({
content: [{ type: "text", text: String(Math.floor(Math.random() * (max - min + 1)) + min) }],
}),
);
const transport = new StdioServerTransport();
await server.connect(transport);
```
This is a simple example. Your MCP server runs inside the sandbox, so you can execute any code you'd like: query databases, call internal APIs, run shell commands, or interact with any service available in the container.
</Step>
<Step title="Package the MCP server">
Bundle into a single JS file so it can be uploaded and executed without a `node_modules` folder.
```bash
npx esbuild src/mcp-server.ts --bundle --format=cjs --platform=node --target=node18 --minify --outfile=dist/mcp-server.cjs
```
This creates `dist/mcp-server.cjs` ready to upload.
</Step>
<Step title="Create sandbox and upload MCP server">
Start your sandbox, then write the bundled file into it.
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
import fs from "node:fs";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
const content = await fs.promises.readFile("./dist/mcp-server.cjs");
await client.writeFsFile(
{ path: "/opt/mcp/custom-tools/mcp-server.cjs" },
content,
);
```
```bash cURL
curl -X PUT "http://127.0.0.1:2468/v1/fs/file?path=/opt/mcp/custom-tools/mcp-server.cjs" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
--data-binary @./dist/mcp-server.cjs
```
</CodeGroup>
</Step>
<Step title="Create a session">
Point an MCP server config at the bundled JS file. When the session starts, Sandbox Agent spawns the MCP server process and routes tool calls to it.
<CodeGroup>
```ts TypeScript
await client.createSession("custom-tools", {
agent: "claude",
mcp: {
customTools: {
type: "local",
command: ["node", "/opt/mcp/custom-tools/mcp-server.cjs"],
},
},
});
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/sessions/custom-tools" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"agent": "claude",
"mcp": {
"customTools": {
"type": "local",
"command": ["node", "/opt/mcp/custom-tools/mcp-server.cjs"]
}
}
}'
```
</CodeGroup>
</Step>
</Steps>
## Option B: Tools via Skills
Skills are markdown files that instruct the agent how to use a script. Upload the script and a skill file, then point the session at the skill directory.
<Steps>
<Step title="Write your script">
Write a script that the agent will execute. This runs inside the sandbox just like an MCP server, but the agent invokes it directly via its shell tool.
```ts src/random-number.ts
const min = Number(process.argv[2]);
const max = Number(process.argv[3]);
if (Number.isNaN(min) || Number.isNaN(max)) {
console.error("Usage: random-number <min> <max>");
process.exit(1);
}
console.log(Math.floor(Math.random() * (max - min + 1)) + min);
```
</Step>
<Step title="Write a skill file">
Create a `SKILL.md` that tells the agent what the script does and how to run it. The frontmatter `name` and `description` fields are required. See [Skill authoring best practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices) for tips on writing effective skills.
```md SKILL.md
---
name: random-number
description: Generate a random integer between min and max (inclusive). Use when the user asks for a random number.
---
To generate a random number, run:
```bash
node /opt/skills/random-number/random-number.cjs <min> <max>
```
This prints a single random integer between min and max (inclusive).
</Step>
<Step title="Package the script">
Bundle the script just like an MCP server so it has no dependencies at runtime.
```bash
npx esbuild src/random-number.ts --bundle --format=cjs --platform=node --target=node18 --minify --outfile=dist/random-number.cjs
```
</Step>
<Step title="Create sandbox and upload files">
Upload both the bundled script and the skill file.
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
import fs from "node:fs";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
const script = await fs.promises.readFile("./dist/random-number.cjs");
await client.writeFsFile(
{ path: "/opt/skills/random-number/random-number.cjs" },
script,
);
const skill = await fs.promises.readFile("./SKILL.md");
await client.writeFsFile(
{ path: "/opt/skills/random-number/SKILL.md" },
skill,
);
```
```bash cURL
curl -X PUT "http://127.0.0.1:2468/v1/fs/file?path=/opt/skills/random-number/random-number.cjs" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
--data-binary @./dist/random-number.cjs
curl -X PUT "http://127.0.0.1:2468/v1/fs/file?path=/opt/skills/random-number/SKILL.md" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
--data-binary @./SKILL.md
```
</CodeGroup>
</Step>
<Step title="Create a session">
Point the session at the skill directory. The agent reads `SKILL.md` and learns how to use your script.
<CodeGroup>
```ts TypeScript
await client.createSession("custom-tools", {
agent: "claude",
skills: {
sources: [
{ type: "local", source: "/opt/skills/random-number" },
],
},
});
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/sessions/custom-tools" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"agent": "claude",
"skills": {
"sources": [
{ "type": "local", "source": "/opt/skills/random-number" }
]
}
}'
```
</CodeGroup>
</Step>
</Steps>
## Notes
- The sandbox image must include a Node.js runtime that can execute the bundled files.

View file

@ -1,27 +0,0 @@
---
title: "Deploy"
sidebarTitle: "Overview"
description: "Choose where to run the sandbox-agent server."
icon: "server"
---
<CardGroup cols={2}>
<Card title="Local" icon="laptop" href="/deploy/local">
Run locally for development. The SDK can auto-spawn the server.
</Card>
<Card title="E2B" icon="cube" href="/deploy/e2b">
Deploy inside an E2B sandbox with network access.
</Card>
<Card title="Vercel" icon="triangle" href="/deploy/vercel">
Deploy inside a Vercel Sandbox with port forwarding.
</Card>
<Card title="Cloudflare" icon="cloud" href="/deploy/cloudflare">
Deploy inside a Cloudflare Sandbox with port exposure.
</Card>
<Card title="Daytona" icon="cloud" href="/deploy/daytona">
Run in a Daytona workspace with port forwarding.
</Card>
<Card title="Docker" icon="docker" href="/deploy/docker">
Build and run in a container (development only).
</Card>
</CardGroup>

View file

@ -25,66 +25,97 @@
},
"navbar": {
"links": [
{
"label": "Gigacode",
"icon": "terminal",
"href": "https://github.com/rivet-dev/sandbox-agent/tree/main/gigacode"
},
{
"label": "Discord",
"icon": "discord",
"href": "https://discord.gg/auCecybynK"
},
{
"label": "GitHub",
"icon": "github",
"type": "github",
"href": "https://github.com/rivet-dev/sandbox-agent"
}
]
},
"navigation": {
"pages": [
"tabs": [
{
"group": "Getting started",
"tab": "Documentation",
"pages": [
"quickstart",
"building-chat-ui",
"manage-sessions",
"opencode-compatibility"
]
},
{
"group": "Deploy",
"pages": [
"deploy/index",
"deploy/local",
"deploy/e2b",
"deploy/daytona",
"deploy/vercel",
"deploy/cloudflare",
"deploy/docker"
]
},
{
"group": "SDKs",
"pages": ["sdks/typescript", "sdks/python"]
},
{
"group": "Reference",
"pages": [
"cli",
"inspector",
"session-transcript-schema",
"credentials",
"gigacode",
{
"group": "AI",
"pages": ["ai/skill", "ai/llms-txt"]
"group": "Getting started",
"pages": [
"quickstart",
"building-chat-ui",
"manage-sessions",
{
"group": "Deploy",
"icon": "server",
"pages": [
"deploy/local",
"deploy/e2b",
"deploy/daytona",
"deploy/vercel",
"deploy/cloudflare",
"deploy/docker"
]
}
]
},
{
"group": "Advanced",
"pages": ["daemon", "cors", "telemetry"]
"group": "SDKs",
"pages": ["sdks/typescript", "sdks/python"]
},
{
"group": "Agent Features",
"pages": [
"agent-sessions",
"attachments",
"skills",
"mcp",
"custom-tools"
]
},
{
"group": "Features",
"pages": ["file-system"]
},
{
"group": "Reference",
"pages": [
"cli",
"inspector",
"session-transcript-schema",
"opencode-compatibility",
{
"group": "More",
"pages": [
"credentials",
"daemon",
"cors",
"telemetry",
{
"group": "AI",
"pages": ["ai/skill", "ai/llms-txt"]
}
]
}
]
}
]
},
{
"group": "HTTP API Reference",
"openapi": "openapi.json"
"tab": "HTTP API",
"pages": [
{
"group": "HTTP Reference",
"openapi": "openapi.json"
}
]
}
]
}

184
docs/file-system.mdx Normal file
View file

@ -0,0 +1,184 @@
---
title: "File System"
description: "Read, write, and manage files inside the sandbox."
sidebarTitle: "File System"
icon: "folder"
---
The filesystem API lets you list, read, write, move, and delete files inside the sandbox, plus upload batches of files via tar archives.
## Path Resolution
- Absolute paths are used as-is.
- Relative paths use the session working directory when `sessionId` is provided.
- Without `sessionId`, relative paths resolve against the server home directory.
- Relative paths cannot contain `..` or absolute prefixes; requests that attempt to escape the root are rejected.
The session working directory is the server process current working directory at the moment the session is created.
## List Entries
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
const entries = await client.listFsEntries({
path: "./workspace",
sessionId: "my-session",
});
console.log(entries);
```
```bash cURL
curl -X GET "http://127.0.0.1:2468/v1/fs/entries?path=./workspace&sessionId=my-session" \
-H "Authorization: Bearer $SANDBOX_TOKEN"
```
</CodeGroup>
## Read And Write Files
`PUT /v1/fs/file` writes raw bytes. `GET /v1/fs/file` returns raw bytes.
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.writeFsFile({ path: "./notes.txt", sessionId: "my-session" }, "hello");
const bytes = await client.readFsFile({
path: "./notes.txt",
sessionId: "my-session",
});
const text = new TextDecoder().decode(bytes);
console.log(text);
```
```bash cURL
curl -X PUT "http://127.0.0.1:2468/v1/fs/file?path=./notes.txt&sessionId=my-session" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
--data-binary "hello"
curl -X GET "http://127.0.0.1:2468/v1/fs/file?path=./notes.txt&sessionId=my-session" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
--output ./notes.txt
```
</CodeGroup>
## Create Directories
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.mkdirFs({
path: "./data",
sessionId: "my-session",
});
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/fs/mkdir?path=./data&sessionId=my-session" \
-H "Authorization: Bearer $SANDBOX_TOKEN"
```
</CodeGroup>
## Move, Delete, And Stat
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.moveFs(
{ from: "./notes.txt", to: "./notes-old.txt", overwrite: true },
{ sessionId: "my-session" },
);
const stat = await client.statFs({
path: "./notes-old.txt",
sessionId: "my-session",
});
await client.deleteFsEntry({
path: "./notes-old.txt",
sessionId: "my-session",
});
console.log(stat);
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/fs/move?sessionId=my-session" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"from":"./notes.txt","to":"./notes-old.txt","overwrite":true}'
curl -X GET "http://127.0.0.1:2468/v1/fs/stat?path=./notes-old.txt&sessionId=my-session" \
-H "Authorization: Bearer $SANDBOX_TOKEN"
curl -X DELETE "http://127.0.0.1:2468/v1/fs/entry?path=./notes-old.txt&sessionId=my-session" \
-H "Authorization: Bearer $SANDBOX_TOKEN"
```
</CodeGroup>
## Batch Upload (Tar)
Batch upload accepts `application/x-tar` only and extracts into the destination directory. The response returns absolute paths for extracted files, capped at 1024 entries.
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
import fs from "node:fs";
import path from "node:path";
import tar from "tar";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
const archivePath = path.join(process.cwd(), "skills.tar");
await tar.c({
cwd: "./skills",
file: archivePath,
}, ["."]);
const tarBuffer = await fs.promises.readFile(archivePath);
const result = await client.uploadFsBatch(tarBuffer, {
path: "./skills",
sessionId: "my-session",
});
console.log(result);
```
```bash cURL
tar -cf skills.tar -C ./skills .
curl -X POST "http://127.0.0.1:2468/v1/fs/upload-batch?path=./skills&sessionId=my-session" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/x-tar" \
--data-binary @skills.tar
```
</CodeGroup>

View file

@ -1,7 +1,6 @@
---
title: "Inspector"
description: "Debug and inspect agent sessions with the Inspector UI."
icon: "magnifying-glass"
---
The Inspector is a web-based GUI for debugging and inspecting Sandbox Agent sessions. Use it to view events, send messages, and troubleshoot agent behavior in real-time.

122
docs/mcp.mdx Normal file
View file

@ -0,0 +1,122 @@
---
title: "MCP"
description: "Configure MCP servers for agent sessions."
sidebarTitle: "MCP"
icon: "plug"
---
MCP (Model Context Protocol) servers extend agents with tools. Sandbox Agent can auto-load MCP servers when a session starts by passing an `mcp` map in the create-session request.
## Session Config
The `mcp` field is a map of server name to config. Use `type: "local"` for stdio servers and `type: "remote"` for HTTP/SSE servers:
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.createSession("claude-mcp", {
agent: "claude",
mcp: {
filesystem: {
type: "local",
command: "my-mcp-server",
args: ["--root", "."],
},
github: {
type: "remote",
url: "https://example.com/mcp",
headers: {
Authorization: "Bearer ${GITHUB_TOKEN}",
},
},
},
});
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/sessions/claude-mcp" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"agent": "claude",
"mcp": {
"filesystem": {
"type": "local",
"command": "my-mcp-server",
"args": ["--root", "."]
},
"github": {
"type": "remote",
"url": "https://example.com/mcp",
"headers": {
"Authorization": "Bearer ${GITHUB_TOKEN}"
}
}
}
}'
```
</CodeGroup>
## Config Fields
### Local Server
Stdio servers that run inside the sandbox.
| Field | Description |
|---|---|
| `type` | `local` |
| `command` | string or array (`["node", "server.js"]`) |
| `args` | array of string arguments |
| `env` | environment variables map |
| `enabled` | enable or disable the server |
| `timeoutMs` | tool timeout override |
| `cwd` | working directory for the MCP process |
```json
{
"type": "local",
"command": ["node", "./mcp/server.js"],
"args": ["--root", "."],
"env": { "LOG_LEVEL": "debug" },
"cwd": "/workspace"
}
```
### Remote Server
HTTP/SSE servers accessed over the network.
| Field | Description |
|---|---|
| `type` | `remote` |
| `url` | MCP server URL |
| `headers` | static headers map |
| `bearerTokenEnvVar` | env var name to inject into `Authorization: Bearer ...` |
| `envHeaders` | map of header name to env var name |
| `oauth` | object with `clientId`, `clientSecret`, `scope`, or `false` to disable |
| `enabled` | enable or disable the server |
| `timeoutMs` | tool timeout override |
| `transport` | `http` or `sse` |
```json
{
"type": "remote",
"url": "https://example.com/mcp",
"headers": { "x-client": "sandbox-agent" },
"bearerTokenEnvVar": "MCP_TOKEN",
"transport": "sse"
}
```
## Custom MCP Servers
To bundle and upload your own MCP server into the sandbox, see [Custom Tools](/custom-tools).

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,6 @@
---
title: "OpenCode SDK & UI Support"
title: "OpenCode Compatibility"
description: "Connect OpenCode clients, SDKs, and web UI to Sandbox Agent."
icon: "rectangle-terminal"
---
<Warning>

View file

@ -1,7 +1,6 @@
---
title: "Session Transcript Schema"
description: "Universal event schema for session transcripts across all agents."
icon: "brackets-curly"
---
Each coding agent outputs events in its own native format. The sandbox-agent converts these into a universal event schema, giving you a consistent session transcript regardless of which agent you use.
@ -27,7 +26,7 @@ This table shows which agent feature coverage appears in the universal event str
| Reasoning/Thinking | - | ✓ | - | - |
| Command Execution | - | ✓ | - | - |
| File Changes | - | ✓ | - | - |
| MCP Tools | - | ✓ | - | - |
| MCP Tools | ✓ | ✓ | ✓ | ✓ |
| Streaming Deltas | ✓ | ✓ | ✓ | - |
| Variants | | ✓ | ✓ | ✓ |

87
docs/skills.mdx Normal file
View file

@ -0,0 +1,87 @@
---
title: "Skills"
description: "Auto-load skills into agent sessions."
sidebarTitle: "Skills"
icon: "sparkles"
---
Skills are local instruction bundles stored in `SKILL.md` files. Sandbox Agent can fetch, discover, and link skill directories into agent-specific skill paths at session start using the `skills.sources` field. The format is fully compatible with [skills.sh](https://skills.sh).
## Session Config
Pass `skills.sources` when creating a session to load skills from GitHub repos, local paths, or git URLs.
<CodeGroup>
```ts TypeScript
import { SandboxAgent } from "sandbox-agent";
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.createSession("claude-skills", {
agent: "claude",
skills: {
sources: [
{ type: "github", source: "rivet-dev/skills", skills: ["sandbox-agent"] },
{ type: "local", source: "/workspace/my-custom-skill" },
],
},
});
```
```bash cURL
curl -X POST "http://127.0.0.1:2468/v1/sessions/claude-skills" \
-H "Authorization: Bearer $SANDBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"agent": "claude",
"skills": {
"sources": [
{ "type": "github", "source": "rivet-dev/skills", "skills": ["sandbox-agent"] },
{ "type": "local", "source": "/workspace/my-custom-skill" }
]
}
}'
```
</CodeGroup>
Each skill directory must contain `SKILL.md`. See [Skill authoring best practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices) for tips on writing effective skills.
## Skill Sources
Each entry in `skills.sources` describes where to find skills. Three source types are supported:
| Type | `source` value | Example |
|------|---------------|---------|
| `github` | `owner/repo` | `"rivet-dev/skills"` |
| `local` | Filesystem path | `"/workspace/my-skill"` |
| `git` | Git clone URL | `"https://git.example.com/skills.git"` |
### Optional fields
- **`skills`** — Array of skill directory names to include. When omitted, all discovered skills are installed.
- **`ref`** — Branch, tag, or commit to check out (default: HEAD). Applies to `github` and `git` types.
- **`subpath`** — Subdirectory within the repo to search for skills.
## Custom Skills
To write, upload, and configure your own skills inside the sandbox, see [Custom Tools](/custom-tools).
## Advanced
### Discovery logic
After resolving a source to a local directory (cloning if needed), Sandbox Agent discovers skills by:
1. Checking if the directory itself contains `SKILL.md`.
2. Scanning `skills/` subdirectory for child directories containing `SKILL.md`.
3. Scanning immediate children of the directory for `SKILL.md`.
Discovered skills are symlinked into project-local skill roots (`.claude/skills/<name>`, `.agents/skills/<name>`, `.opencode/skill/<name>`).
### Caching
GitHub sources are downloaded as zip archives and git sources are cloned to `~/.sandbox-agent/skills-cache/` and updated on subsequent session creations. GitHub sources do not require `git` to be installed.