docs: rewrite SMFS provider guides to use mount + Claude Agents SDK

All four guides now show the mount pattern as the primary approach:
mount SMFS inside the sandbox, then run a Claude agent with bash
tool access so it reads/writes memory using standard commands.

- E2B: tested end-to-end (install, login, mount, read, write, grep)
- Daytona: mount pattern with TLS warning
- Vercel AI SDK: SMFS mounted on host, bash tool for the agent
- Cloudflare: Container with SMFS pre-installed in Dockerfile
This commit is contained in:
Dhravya 2026-04-27 22:48:40 +00:00
parent 8ae6b708a9
commit faeef886ee
4 changed files with 361 additions and 642 deletions

View file

@ -1,205 +1,122 @@
---
title: "Cloudflare"
sidebarTitle: "Cloudflare"
description: "Add persistent memory to Cloudflare Workers agents with SMFS."
icon: "cloud"
description: "Give your AI agent persistent memory inside a Cloudflare Container using SMFS"
---
[Cloudflare Workers](https://workers.cloudflare.com) run at the edge in V8 isolates — no filesystem, no shell. That's exactly what `@supermemory/bash` is built for. It gives your Worker a virtual bash environment backed by Supermemory, so your agent can `ls`, `cat`, `grep`, and write to a persistent memory container without needing a real filesystem.
Mount a Supermemory container inside a
[Cloudflare Container](https://developers.cloudflare.com/containers/) so your
agent can read and write memory with plain bash commands.
## Architecture
## How it works
Cloudflare Workers can't mount SMFS (no FUSE, no disk). Instead, use `@supermemory/bash` as a tool for your agent. The bash tool runs entirely in-process — no child processes, no disk I/O, no native dependencies.
```
Request → Worker → LLM → calls bash tool → @supermemory/bash → Supermemory API
```
<Note>
If you're using [Cloudflare Containers](https://developers.cloudflare.com/containers/) (full Linux containers at the edge), you can install the `smfs` binary directly. See [Alternative: Cloudflare Containers](#alternative-cloudflare-containers) below.
</Note>
1. Build a container image with SMFS pre-installed
2. Deploy it as a Cloudflare Container
3. On startup, mount a Supermemory container inside the container
4. Run a Claude agent with bash access — it reads/writes the SMFS mount naturally
## Prerequisites
- A [Supermemory](https://console.supermemory.ai) account and API key
- A [Cloudflare](https://dash.cloudflare.com) account
- Node.js 18+ and Wrangler CLI
- A [Supermemory API key](https://supermemory.ai)
- An [Anthropic API key](https://console.anthropic.com)
- A [Cloudflare account](https://dash.cloudflare.com) with Containers enabled
- [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/)
## 1. Set up a Worker
## Container setup
```bash
npm create cloudflare@latest -- my-memory-agent
cd my-memory-agent
npm install @supermemory/bash
```
Add your Supermemory API key as a secret:
```bash
npx wrangler secret put SUPERMEMORY_API_KEY
```
## 2. Build an agent with memory
```typescript src/index.ts
import { createBash } from "@supermemory/bash";
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const { bash, toolDescription } = await createBash({
apiKey: env.SUPERMEMORY_API_KEY,
containerTag: "user_42",
});
// Read the user's profile
const profile = await bash.exec("cat /profile.md");
// Search memory semantically
const results = await bash.exec("sgrep 'project deadlines'");
// Write new memory
await bash.exec('echo "Met with client on April 27" >> /notes.md');
return new Response(JSON.stringify({
profile: profile.stdout,
search: results.stdout,
}));
},
};
```
## 3. Full agent with tool calling
Wire `@supermemory/bash` as a tool for an LLM. This example uses the OpenAI API, but any provider works:
```typescript src/index.ts
import { createBash } from "@supermemory/bash";
interface Env {
SUPERMEMORY_API_KEY: string;
OPENAI_API_KEY: string;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const { messages, userId } = await request.json() as {
messages: any[];
userId: string;
};
const { bash, toolDescription } = await createBash({
apiKey: env.SUPERMEMORY_API_KEY,
containerTag: `user_${userId}`,
});
// Call the LLM with the bash tool
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${env.OPENAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "gpt-4o",
messages: [
{
role: "system",
content: `You have persistent memory via a bash tool.
Use it to remember things about the user.
Start by reading /profile.md for context.`,
},
...messages,
],
tools: [{
type: "function",
function: {
name: "bash",
description: toolDescription,
parameters: {
type: "object",
properties: { cmd: { type: "string" } },
required: ["cmd"],
},
},
}],
}),
});
const data = await response.json() as any;
// Handle tool calls
if (data.choices[0].message.tool_calls) {
const toolCall = data.choices[0].message.tool_calls[0];
const cmd = JSON.parse(toolCall.function.arguments).cmd;
const result = await bash.exec(cmd);
// Send the result back to the LLM
const followUp = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${env.OPENAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "gpt-4o",
messages: [
...messages,
data.choices[0].message,
{
role: "tool",
tool_call_id: toolCall.id,
content: JSON.stringify(result),
},
],
}),
});
const followUpData = await followUp.json() as any;
return new Response(followUpData.choices[0].message.content);
}
return new Response(data.choices[0].message.content);
},
};
```
## Alternative: Cloudflare Containers
[Cloudflare Containers](https://developers.cloudflare.com/containers/) give you full Linux environments at the edge. Unlike Workers, containers have a real filesystem and shell — so you can install and mount SMFS directly.
### Dockerfile
```dockerfile Dockerfile
FROM node:20-slim
# Install FUSE and bash
RUN apt-get update && apt-get install -y fuse3 curl bash && rm -rf /var/lib/apt/lists/*
RUN echo 'user_allow_other' >> /etc/fuse.conf
# Install SMFS
RUN curl -fsSL https://smfs.ai/install | bash
# Your agent code
COPY . /app
WORKDIR /app
RUN npm install
# Install the Claude Agent SDK
RUN npm install -g @anthropic-ai/claude-agent-sdk
CMD ["node", "agent.js"]
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
```
Inside the container, mount SMFS as you would on any Linux machine:
### Entrypoint
```bash
smfs login --key $SUPERMEMORY_API_KEY
smfs mount agent_memory --ephemeral --path /memory
```bash entrypoint.sh
#!/bin/bash
set -e
# Log in and mount
smfs login --key "$SUPERMEMORY_API_KEY"
smfs mount my_agent --ephemeral --path /memory --foreground &
sleep 5
# Run the agent
node agent.js
```
Your agent can then use standard Unix commands to interact with memory.
### Agent
```typescript agent.ts
import { query } from "@anthropic-ai/claude-agent-sdk";
async function main() {
for await (const message of query({
prompt: `You have access to a persistent memory filesystem mounted at /memory.
Use bash commands to explore it (ls, cat) and write notes to it (echo "..." > file).
Read /memory/profile.md to learn about the user.
Then create /memory/session_notes.md with a summary of what you found.`,
options: {
allowedTools: ["Bash", "Read", "Write"],
},
})) {
if (message.type === "text") console.log(message.text);
}
}
main();
```
## Worker + Container pattern
Use a Cloudflare Worker as the HTTP frontend that triggers the container:
```typescript worker.ts
export default {
async fetch(request: Request, env: any) {
// Start the container (it runs the agent with SMFS mounted)
const container = await env.MY_CONTAINER.start();
// The container runs the agent and writes results to SMFS
// Read the result back
const response = await container.fetch("/result");
return response;
},
};
```
```toml wrangler.toml
name = "memory-agent"
main = "worker.ts"
[[containers]]
class_name = "MY_CONTAINER"
image = "./Dockerfile"
max_instances = 5
```
## Tips
- **Workers have a 30-second CPU time limit.** Keep tool call chains short. If your agent needs many steps, consider using Durable Objects for longer-running workflows.
- **One container tag per user.** Use the user's ID as the container tag for isolated memory per user.
- **`sgrep` for semantic search.** Inside the bash tool, `sgrep "query"` searches by meaning. Regular `grep` does literal matching.
- **Cache-friendly.** `@supermemory/bash` warms its path index on `createBash`. For Workers that handle many requests, consider caching the instance in a Durable Object.
## Resources
- [Cloudflare Workers docs](https://developers.cloudflare.com/workers/)
- [Cloudflare Containers docs](https://developers.cloudflare.com/containers/)
- [SMFS Bash Tool reference](/smfs/bash-tool)
- [Supermemory quickstart](/quickstart)
- Use `--ephemeral` when mounting inside containers — it keeps the cache in memory
only, but writes still push to Supermemory
- Use `smfs grep 'query'` for semantic search across all files in the container
- Set `SUPERMEMORY_API_KEY` and `ANTHROPIC_API_KEY` as Cloudflare secrets:
```bash
wrangler secret put SUPERMEMORY_API_KEY
wrangler secret put ANTHROPIC_API_KEY
```

View file

@ -1,121 +1,71 @@
---
title: "Daytona"
sidebarTitle: "Daytona"
description: "Give your Daytona sandboxes persistent memory with SMFS."
icon: "server"
description: "Give your AI agent persistent memory inside a Daytona sandbox using SMFS"
---
[Daytona](https://www.daytona.io) gives AI agents isolated Linux sandboxes that boot in milliseconds. Pair it with SMFS and your agent gets both safe code execution **and** persistent memory it can `ls`, `cat`, and `grep`.
Mount a Supermemory container inside a [Daytona](https://daytona.io) sandbox so
your agent can read and write memory with plain bash commands.
## Architecture
## How it works
Daytona sandboxes run full Linux with shell access, filesystem, and network. There are two ways to wire SMFS in:
<CardGroup cols={2}>
<Card title="Bash Tool in your agent code" icon="terminal">
Use `@supermemory/bash` in the code that **orchestrates** the sandbox. The agent reads memory via the bash tool, then sends code to Daytona for execution. Works everywhere.
</Card>
<Card title="Mount inside the sandbox" icon="hard-drive">
Install the `smfs` binary inside the sandbox and mount a container directly. Requires unrestricted outbound HTTPS from the sandbox.
</Card>
</CardGroup>
<Note>
Some Daytona sandbox configurations may restrict outbound TLS to certain hosts. If `smfs mount` or `smfs login` fails with connection errors, use the Bash Tool pattern instead — it runs in your orchestrating code, not inside the sandbox.
</Note>
1. Create a Daytona sandbox
2. Install SMFS and mount a Supermemory container inside it
3. Run a Claude agent inside the sandbox — it uses `cat`, `ls`, `echo`, etc. on the mount
4. Everything the agent writes is persisted to Supermemory automatically
## Prerequisites
- A [Supermemory](https://console.supermemory.ai) account and API key
- A [Daytona](https://app.daytona.io) account and API key
- Node.js 18+ or Python 3.10+
- A [Supermemory API key](https://supermemory.ai)
- A [Daytona API key](https://app.daytona.io) — go to **API Keys** in the sidebar
- An [Anthropic API key](https://console.anthropic.com)
## 1. Get your API keys
### Supermemory
1. Go to [console.supermemory.ai](https://console.supermemory.ai)
2. Navigate to **Settings → API Keys**
3. Create a new key and copy it
### Daytona
1. Go to [app.daytona.io](https://app.daytona.io)
2. Sign up and verify your email
3. Set your default region (US or EU)
4. Navigate to **API Keys** in the sidebar
5. Click **Create Key**, give it a name, and copy the key
<Warning>
You can only view a Daytona API key once. Store it somewhere safe immediately after creation.
</Warning>
## 2. Install the SDKs
## Quick start
<Tabs>
<Tab title="TypeScript">
```bash
npm install @supermemory/bash @daytonaio/sdk
npm install @anthropic-ai/claude-agent-sdk @daytonaio/sdk
```
</Tab>
<Tab title="Python">
```bash
pip install daytona-sdk
```
</Tab>
</Tabs>
## 3. Build an agent with memory + code execution
<Tabs>
<Tab title="TypeScript">
The recommended TypeScript pattern: use `@supermemory/bash` for memory in your orchestrating code and the Daytona SDK for code execution. The LLM gets both as tools.
```typescript agent.ts
import { createBash } from "@supermemory/bash";
import { Daytona } from "@daytonaio/sdk";
import { generateText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
import { query } from "@anthropic-ai/claude-agent-sdk";
async function main() {
// 1. Set up memory (SMFS bash tool)
const { bash, toolDescription } = await createBash({
apiKey: process.env.SUPERMEMORY_API_KEY!,
containerTag: "agent_memory",
});
// 2. Set up code execution (Daytona sandbox)
// 1. Create a Daytona sandbox
const daytona = new Daytona({
apiKey: process.env.DAYTONA_API_KEY!,
apiUrl: "https://app.daytona.io/api",
});
const sandbox = await daytona.create();
// 3. Give the LLM both tools
const result = await generateText({
model: openai("gpt-4o"),
tools: {
memory: tool({
description: toolDescription,
parameters: z.object({ cmd: z.string() }),
execute: async ({ cmd }) => bash.exec(cmd),
}),
execute_code: tool({
description: "Run code in an isolated sandbox",
parameters: z.object({ code: z.string() }),
execute: async ({ code }) => {
const res = await sandbox.process.exec(code);
return res.result;
},
}),
},
prompt: "Check my memory for the user's preferred language, then write and run a hello world in that language.",
});
// 2. Install SMFS, log in, and mount
await sandbox.process.exec("curl -fsSL https://smfs.ai/install | bash");
await sandbox.process.exec(
`~/.local/bin/smfs login --key ${process.env.SUPERMEMORY_API_KEY}`
);
await sandbox.process.exec(
"~/.local/bin/smfs mount my_agent --ephemeral --path /home/daytona/memory"
);
console.log(result.text);
// 3. Run a Claude agent inside the sandbox with bash access
for await (const message of query({
prompt: `You have access to a persistent memory filesystem mounted at /home/daytona/memory.
Use bash commands to explore it (ls, cat) and write notes to it (echo "..." > file).
First, read /home/daytona/memory/profile.md to learn about the user.
Then create /home/daytona/memory/session_notes.md with a summary of what you found.`,
options: {
allowedTools: ["Bash", "Read", "Write"],
},
})) {
if (message.type === "text") console.log(message.text);
}
// 4. Clean up
await sandbox.process.exec(
"~/.local/bin/smfs unmount my_agent 2>/dev/null"
);
await daytona.delete(sandbox);
}
@ -123,64 +73,66 @@ Daytona sandboxes run full Linux with shell access, filesystem, and network. The
```
</Tab>
<Tab title="Python">
In Python, install and mount SMFS inside the Daytona sandbox. The agent reads and writes memory via standard shell commands.
<Warning>
This requires unrestricted outbound HTTPS from the sandbox. If `smfs login` fails with a connection error, see the note at the top of this page.
</Warning>
```bash
pip install claude-agent-sdk daytona-sdk
```
```python agent.py
import asyncio
import os
from claude_agent_sdk import query, ClaudeAgentOptions
from daytona_sdk import Daytona, DaytonaConfig
# 1. Set up code execution (Daytona sandbox)
config = DaytonaConfig(
api_key=os.environ["DAYTONA_API_KEY"],
api_url="https://app.daytona.io/api",
)
daytona = Daytona(config)
sandbox = daytona.create()
async def main():
# 1. Create a Daytona sandbox
config = DaytonaConfig(
api_key=os.environ["DAYTONA_API_KEY"],
api_url="https://app.daytona.io/api",
)
daytona = Daytona(config)
sandbox = daytona.create()
# 2. Install SMFS inside the sandbox
sandbox.process.exec(
"curl -fsSL https://smfs.ai/install | bash"
)
# 2. Install SMFS, log in, and mount
sandbox.process.exec("curl -fsSL https://smfs.ai/install | bash")
sandbox.process.exec(
f"~/.local/bin/smfs login --key {os.environ['SUPERMEMORY_API_KEY']}"
)
sandbox.process.exec(
"~/.local/bin/smfs mount my_agent --ephemeral --path /home/daytona/memory"
)
# 3. Log in and mount
sandbox.process.exec(
f"~/.local/bin/smfs login --key {os.environ['SUPERMEMORY_API_KEY']}"
)
sandbox.process.exec(
"~/.local/bin/smfs mount agent_memory --ephemeral"
)
# 3. Run a Claude agent inside the sandbox with bash access
async for message in query(
prompt="""You have access to a persistent memory filesystem mounted at /home/daytona/memory.
Use bash commands to explore it (ls, cat) and write notes to it.
# 4. Read the auto-generated profile
response = sandbox.process.exec("cat agent_memory/profile.md")
print(response.result)
First, read /home/daytona/memory/profile.md to learn about the user.
Then create /home/daytona/memory/session_notes.md with a summary of what you found.""",
options=ClaudeAgentOptions(
allowed_tools=["Bash", "Read", "Write"],
),
):
print(message)
# 5. Semantic search
response = sandbox.process.exec(
"~/.local/bin/smfs grep 'preferred language'"
)
print(response.result)
# 4. Clean up
sandbox.process.exec("~/.local/bin/smfs unmount my_agent 2>/dev/null")
daytona.delete(sandbox)
# 6. Clean up
sandbox.process.exec("~/.local/bin/smfs unmount agent_memory")
daytona.delete(sandbox)
asyncio.run(main())
```
</Tab>
</Tabs>
<Note>
Some Daytona datacenter IPs may be blocked by upstream firewalls. If
`smfs login` or `smfs mount` fails with a TLS connection error, check
that outbound HTTPS to `api.supermemory.ai` is not restricted.
</Note>
## Tips
- **Use `--ephemeral` for sandboxes.** Sandbox filesystems are temporary. Ephemeral mode avoids writing a local SQLite cache that will be thrown away.
- **One container, many sandboxes.** Mount the same container tag from multiple sandboxes. Bidirectional sync keeps them in step.
- **Give each agent a subdirectory.** If multiple agents share a container, scope them to `/agent_a/`, `/agent_b/`, etc. They can still read across the whole mount.
- **Clean up sandboxes.** Call `daytona.delete(sandbox)` when done to avoid burning through free credits.
## Resources
- [Daytona docs](https://www.daytona.io/docs)
- [Daytona SDK reference](https://www.daytona.io/docs/en/tools/api/)
- [SMFS Mount reference](/smfs/mount)
- [SMFS Bash Tool reference](/smfs/bash-tool)
- Use `--ephemeral` when mounting inside sandboxes — it keeps the cache in memory
only, but writes still push to Supermemory
- Use `smfs grep 'query'` for semantic search across all files in the container
- The agent can write structured data (JSON, markdown) to the mount and it
persists across sandbox sessions via Supermemory

View file

@ -1,108 +1,71 @@
---
title: "E2B"
sidebarTitle: "E2B"
description: "Give your E2B sandboxes persistent memory with SMFS."
icon: "cube"
description: "Give your AI agent persistent memory inside an E2B sandbox using SMFS"
---
[E2B](https://e2b.dev) runs AI-generated code in secure Firecracker microVMs. Pair it with SMFS and your agent gets both safe code execution **and** persistent memory it can `ls`, `cat`, and `grep`.
Mount a Supermemory container inside an [E2B](https://e2b.dev) sandbox so your
agent can read and write memory with plain bash commands.
## Architecture
## How it works
E2B sandboxes are ephemeral Linux microVMs with full shell access and unrestricted network. Two ways to wire SMFS in:
<CardGroup cols={2}>
<Card title="Mount inside the sandbox" icon="hard-drive">
Install the `smfs` binary inside the sandbox and mount a container. The agent uses standard Unix commands to read and write memory.
</Card>
<Card title="Bash Tool in your agent code" icon="terminal">
Use `@supermemory/bash` in the code that **orchestrates** the sandbox. Memory lives in your agent code; code execution lives in E2B.
</Card>
</CardGroup>
1. Create an E2B sandbox
2. Install SMFS and mount a Supermemory container inside it
3. Run a Claude agent inside the sandbox — it uses `cat`, `ls`, `echo`, etc. on the mount
4. Everything the agent writes is persisted to Supermemory automatically
## Prerequisites
- A [Supermemory](https://console.supermemory.ai) account and API key
- An [E2B](https://e2b.dev) account and API key
- Node.js 18+ or Python 3.10+
- A [Supermemory API key](https://supermemory.ai)
- An [E2B API key](https://e2b.dev)
- An [Anthropic API key](https://console.anthropic.com)
## 1. Get your API keys
### Supermemory
1. Go to [console.supermemory.ai](https://console.supermemory.ai)
2. Navigate to **Settings → API Keys**
3. Create a new key and copy it
### E2B
1. Go to [e2b.dev](https://e2b.dev) and sign up
2. Open the [Dashboard](https://e2b.dev/dashboard)
3. Navigate to **API Keys**
4. Copy your API key
## 2. Install the SDKs
## Quick start
<Tabs>
<Tab title="TypeScript">
```bash
npm install @supermemory/bash @e2b/code-interpreter
npm install @anthropic-ai/claude-agent-sdk @e2b/code-interpreter
```
</Tab>
<Tab title="Python">
```bash
pip install e2b-code-interpreter
```
</Tab>
</Tabs>
## 3. Build an agent with memory + code execution
<Tabs>
<Tab title="TypeScript">
The recommended TypeScript pattern: use `@supermemory/bash` for memory in your orchestrating code and the E2B SDK for code execution. The LLM gets both as tools.
```typescript agent.ts
import { createBash } from "@supermemory/bash";
import { Sandbox } from "@e2b/code-interpreter";
import { generateText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
import { query, ClaudeAgentOptions } from "@anthropic-ai/claude-agent-sdk";
async function main() {
// 1. Set up memory (SMFS bash tool)
const { bash, toolDescription } = await createBash({
apiKey: process.env.SUPERMEMORY_API_KEY!,
containerTag: "agent_memory",
});
// 1. Create an E2B sandbox
const sandbox = await Sandbox.create({ timeoutMs: 300_000 });
// 2. Set up code execution (E2B sandbox)
const sandbox = await Sandbox.create();
// 2. Fix FUSE permissions (required in E2B)
await sandbox.commands.run("sudo chmod 666 /dev/fuse");
await sandbox.commands.run(
"echo 'user_allow_other' | sudo tee -a /etc/fuse.conf > /dev/null"
);
// 3. Give the LLM both tools
const result = await generateText({
model: openai("gpt-4o"),
tools: {
memory: tool({
description: toolDescription,
parameters: z.object({ cmd: z.string() }),
execute: async ({ cmd }) => bash.exec(cmd),
}),
execute_code: tool({
description: "Run Python code in an isolated sandbox",
parameters: z.object({ code: z.string() }),
execute: async ({ code }) => {
const execution = await sandbox.runCode(code);
return execution.text;
},
}),
// 3. Install SMFS, log in, and mount
await sandbox.commands.run("curl -fsSL https://smfs.ai/install | bash");
await sandbox.commands.run(
`~/.local/bin/smfs login --key ${process.env.SUPERMEMORY_API_KEY}`
);
await sandbox.commands.run(
"bash -c '~/.local/bin/smfs mount my_agent --ephemeral --path /home/user/memory --foreground > /tmp/smfs.log 2>&1 & sleep 5'"
);
// 4. Run a Claude agent inside the sandbox with bash access
for await (const message of query({
prompt: `You have access to a persistent memory filesystem mounted at /home/user/memory.
Use bash commands to explore it (ls, cat) and write notes to it (echo "..." > file).
First, read /home/user/memory/profile.md to learn about the user.
Then create /home/user/memory/session_notes.md with a summary of what you found.`,
options: {
allowedTools: ["Bash", "Read", "Write"],
},
prompt: "Check my memory for the user's preferences, then write a script that uses them.",
});
})) {
if (message.type === "text") console.log(message.text);
}
console.log(result.text);
// 4. Clean up
// 5. Clean up
await sandbox.commands.run("~/.local/bin/smfs unmount my_agent 2>/dev/null");
await sandbox.kill();
}
@ -110,122 +73,80 @@ E2B sandboxes are ephemeral Linux microVMs with full shell access and unrestrict
```
</Tab>
<Tab title="Python">
In Python, mount SMFS inside the E2B sandbox. The agent reads and writes memory via standard shell commands.
```bash
pip install claude-agent-sdk e2b-code-interpreter
```
```python agent.py
import asyncio
import os
from claude_agent_sdk import query, ClaudeAgentOptions
from e2b_code_interpreter import Sandbox
# 1. Create an E2B sandbox
sandbox = Sandbox.create(timeout=300)
async def main():
# 1. Create an E2B sandbox
sandbox = Sandbox.create(timeout=300)
# 2. Fix FUSE permissions (required in E2B sandboxes)
sandbox.commands.run("sudo chmod 666 /dev/fuse")
sandbox.commands.run(
"echo 'user_allow_other' | sudo tee -a /etc/fuse.conf > /dev/null"
)
# 2. Fix FUSE permissions (required in E2B)
sandbox.commands.run("sudo chmod 666 /dev/fuse")
sandbox.commands.run(
"echo 'user_allow_other' | sudo tee -a /etc/fuse.conf > /dev/null"
)
# 3. Install SMFS and log in
sandbox.commands.run("curl -fsSL https://smfs.ai/install | bash")
sandbox.commands.run(
f"~/.local/bin/smfs login --key {os.environ['SUPERMEMORY_API_KEY']}"
)
# 3. Install SMFS, log in, and mount
sandbox.commands.run("curl -fsSL https://smfs.ai/install | bash")
sandbox.commands.run(
f"~/.local/bin/smfs login --key {os.environ['SUPERMEMORY_API_KEY']}"
)
sandbox.commands.run(
"bash -c '~/.local/bin/smfs mount my_agent --ephemeral"
" --path /home/user/memory --foreground > /tmp/smfs.log 2>&1"
" & sleep 5'",
timeout=15,
)
# 4. Mount memory
sandbox.commands.run(
"bash -c '~/.local/bin/smfs mount agent_memory --ephemeral"
" --path /home/user/memory --foreground > /tmp/smfs.log 2>&1"
" & sleep 5 && echo MOUNTED'",
timeout=15,
)
# 4. Run a Claude agent inside the sandbox with bash access
async for message in query(
prompt="""You have access to a persistent memory filesystem mounted at /home/user/memory.
Use bash commands to explore it (ls, cat) and write notes to it.
# 5. Read the auto-generated profile
result = sandbox.commands.run("cat /home/user/memory/profile.md")
print(result.stdout)
First, read /home/user/memory/profile.md to learn about the user.
Then create /home/user/memory/session_notes.md with a summary of what you found.""",
options=ClaudeAgentOptions(
allowed_tools=["Bash", "Read", "Write"],
),
):
print(message)
# 6. Semantic search
result = sandbox.commands.run(
"~/.local/bin/smfs grep 'preferred language'"
)
print(result.stdout)
# 5. Clean up
sandbox.commands.run(
"~/.local/bin/smfs unmount my_agent 2>/dev/null", timeout=10
)
sandbox.kill()
# 7. Clean up
sandbox.commands.run(
"~/.local/bin/smfs unmount agent_memory 2>/dev/null",
timeout=10,
)
sandbox.kill()
asyncio.run(main())
```
</Tab>
</Tabs>
## Mount SMFS inside the sandbox
E2B sandboxes have full network access and FUSE support, so you can install and mount SMFS directly. Two setup steps are needed first:
<Warning>
E2B sandboxes require FUSE permission fixes before mounting. Run these commands once after creating the sandbox:
E2B sandboxes require two FUSE permission fixes before mounting:
1. `sudo chmod 666 /dev/fuse` — the device exists but is root-only by default
2. `echo 'user_allow_other' | sudo tee -a /etc/fuse.conf` — needed for the `allow_other` mount option
```bash
sudo chmod 666 /dev/fuse
echo 'user_allow_other' | sudo tee -a /etc/fuse.conf > /dev/null
```
Without these, `smfs mount` will fail with a permission error.
</Warning>
```python
from e2b_code_interpreter import Sandbox
import os
sandbox = Sandbox.create(timeout=300)
# One-time FUSE setup
sandbox.commands.run("sudo chmod 666 /dev/fuse")
sandbox.commands.run(
"echo 'user_allow_other' | sudo tee -a /etc/fuse.conf > /dev/null"
)
# Install SMFS
sandbox.commands.run("curl -fsSL https://smfs.ai/install | bash")
# Log in
sandbox.commands.run(
f"~/.local/bin/smfs login --key {os.environ['SUPERMEMORY_API_KEY']}"
)
# Mount with ephemeral mode (recommended for sandboxes)
# Run in background since mount is a long-running daemon
sandbox.commands.run(
"bash -c '~/.local/bin/smfs mount agent_memory --ephemeral"
" --path /home/user/memory --foreground > /tmp/smfs.log 2>&1"
" & sleep 5 && echo MOUNTED'",
timeout=15,
)
# Read the auto-generated profile
result = sandbox.commands.run("cat /home/user/memory/profile.md")
print(result.stdout)
# Write to memory (use sudo — FUSE mount is owned by root)
sandbox.commands.run(
"sudo bash -c 'echo \"User prefers Python\" > /home/user/memory/notes.md'"
)
# Semantic grep works inside the mount
result = sandbox.commands.run("~/.local/bin/smfs grep 'deadlines'")
print(result.stdout)
# Clean up
sandbox.commands.run("~/.local/bin/smfs unmount agent_memory 2>/dev/null", timeout=10)
sandbox.kill()
```
<Note>
The FUSE mount is owned by root. Writing files requires `sudo` (e.g., `sudo bash -c 'echo "..." > /path/file'`). Reads work without sudo.
The FUSE mount is owned by root. Writing files requires `sudo`
(e.g., `sudo bash -c 'echo "..." > /path/file'`). Reads work without sudo.
The Claude agent handles this automatically when using the Bash tool.
</Note>
## Custom E2B template with SMFS pre-installed
## Custom E2B template
For faster startup, bake SMFS and the FUSE fixes into a custom E2B template:
For production, bake SMFS into a custom E2B template so every sandbox starts
with it pre-installed:
```dockerfile e2b.Dockerfile
FROM e2b/code-interpreter:latest
@ -233,7 +154,8 @@ FROM e2b/code-interpreter:latest
# Pre-install SMFS
RUN curl -fsSL https://smfs.ai/install | bash
# Fix FUSE permissions for SMFS mount
# Fix FUSE permissions
RUN chmod 666 /dev/fuse
RUN echo 'user_allow_other' >> /etc/fuse.conf
```
@ -241,38 +163,12 @@ RUN echo 'user_allow_other' >> /etc/fuse.conf
e2b template build -d e2b.Dockerfile
```
Then use your custom template — no setup needed at runtime:
```python
sandbox = Sandbox.create(template="your-custom-template")
# FUSE device still needs chmod at runtime (device nodes reset on boot)
sandbox.commands.run("sudo chmod 666 /dev/fuse")
# Mount directly
sandbox.commands.run(
f"~/.local/bin/smfs login --key {os.environ['SUPERMEMORY_API_KEY']}"
)
sandbox.commands.run(
"bash -c '~/.local/bin/smfs mount agent_memory --ephemeral"
" --path /home/user/memory --foreground > /tmp/smfs.log 2>&1"
" & sleep 5'",
timeout=15,
)
```
Then your agent code only needs to log in and mount — no install step.
## Tips
- **Use `--ephemeral` for sandboxes.** E2B sandboxes are short-lived. Ephemeral mode avoids writing a local cache that will be thrown away.
- **Always fix FUSE permissions.** E2B sandboxes need `sudo chmod 666 /dev/fuse` and `user_allow_other` in `/etc/fuse.conf` before mounting.
- **Mount in background.** The SMFS daemon is long-running. Use `bash -c '... --foreground &'` with a sleep to let it initialize.
- **Custom templates save time.** Pre-install SMFS in a template to skip the install step on every sandbox boot.
- **E2B sandboxes have a timeout.** Default is 5 minutes. Pass `timeout=300` (or more) when creating the sandbox if your agent needs longer.
- **One container, many sandboxes.** Mount the same container tag from multiple E2B sandboxes. Bidirectional sync keeps them in step.
## Resources
- [E2B docs](https://e2b.dev/docs)
- [E2B SDK reference](https://e2b.dev/docs/sdk-reference)
- [SMFS Mount reference](/smfs/mount)
- [SMFS Bash Tool reference](/smfs/bash-tool)
- Use `--ephemeral` when mounting inside sandboxes — it keeps the cache in memory
only, but writes still push to Supermemory
- Use `smfs grep 'query'` for semantic search across all files in the container
- The agent can write structured data (JSON, markdown) to the mount and it
persists across sandbox sessions via Supermemory

View file

@ -1,63 +1,73 @@
---
title: "Vercel AI SDK"
sidebarTitle: "Vercel AI SDK"
description: "Add persistent memory to agents built with the Vercel AI SDK."
icon: "triangle"
description: "Give your AI agent persistent memory using SMFS with the Vercel AI SDK"
---
The [Vercel AI SDK](https://sdk.vercel.ai) is the most popular framework for building AI agents in TypeScript. SMFS plugs in as a tool — give your agent a `bash` tool backed by `@supermemory/bash` and it can `ls`, `cat`, `grep`, and write to a Supermemory container without any filesystem to manage.
Mount a Supermemory container on your server and give your Vercel AI SDK agent
access to it through a bash tool.
## Architecture
## How it works
The Vercel AI SDK uses a tool-calling pattern: you define tools, the model decides when to call them. `@supermemory/bash` fits this perfectly — it's a single tool that exposes a virtual filesystem backed by Supermemory.
1. Install SMFS on your server and mount a Supermemory container
2. Define a bash tool that runs commands against the mount
3. The Vercel AI SDK agent uses the tool to read/write memory with standard commands
```
User → AI SDK → LLM → calls bash tool → @supermemory/bash → Supermemory API
```
No sandbox needed. The bash tool runs in your server process and handles all the memory operations.
<Note>
The Vercel AI SDK runs in your server process (not in a sandbox). SMFS mounts
directly on the host where your server runs.
</Note>
## Prerequisites
- A [Supermemory](https://console.supermemory.ai) account and API key
- Node.js 18+
- An LLM provider (OpenAI, Anthropic, Google, etc.)
- A [Supermemory API key](https://supermemory.ai)
- An [OpenAI](https://platform.openai.com) or [Anthropic](https://console.anthropic.com) API key
- SMFS installed on your server: `curl -fsSL https://smfs.ai/install | bash`
## 1. Install
## Quick start
```bash
npm install @supermemory/bash ai @ai-sdk/openai zod
npm install ai @ai-sdk/anthropic zod
```
## 2. Create an agent with memory
```typescript agent.ts
import { createBash } from "@supermemory/bash";
import { generateText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";
import { execSync } from "child_process";
// Mount SMFS before starting the server:
// smfs login --key $SUPERMEMORY_API_KEY
// smfs mount my_agent --path ./memory
const MEMORY_PATH = "./memory";
async function main() {
// Set up the SMFS bash tool
const { bash, toolDescription } = await createBash({
apiKey: process.env.SUPERMEMORY_API_KEY!,
containerTag: "user_42",
});
const result = await generateText({
model: openai("gpt-4o"),
model: anthropic("claude-sonnet-4-20250514"),
tools: {
bash: tool({
description: toolDescription,
parameters: z.object({ cmd: z.string() }),
execute: async ({ cmd }) => bash.exec(cmd),
description:
"Run a bash command. The persistent memory filesystem is at " +
MEMORY_PATH,
parameters: z.object({ command: z.string() }),
execute: async ({ command }) => {
try {
return execSync(command, {
cwd: MEMORY_PATH,
encoding: "utf-8",
timeout: 10_000,
});
} catch (e: any) {
return e.stderr || e.message;
}
},
}),
},
maxSteps: 10,
system: `You have access to a persistent memory filesystem via the bash tool.
Use it to remember things about the user across conversations.
Start by reading /profile.md to see what you already know.`,
prompt: "What do you remember about me?",
prompt: `You have access to a persistent memory filesystem at ${MEMORY_PATH}.
Use the bash tool to explore it (ls, cat) and write notes (echo "..." > file).
Read profile.md to learn about the user, then create session_notes.md with a summary.`,
});
console.log(result.text);
@ -66,103 +76,47 @@ Start by reading /profile.md to see what you already know.`,
main();
```
That's it. The model will call `bash({ cmd: "cat /profile.md" })` to read the user's profile, `bash({ cmd: "ls /" })` to browse memory, and `bash({ cmd: "grep 'preferences'" })` to search semantically.
## Streaming
## 3. Multi-step agent with memory
A more complete example with conversation history and memory persistence:
```typescript chat.ts
import { createBash } from "@supermemory/bash";
import { generateText, tool, CoreMessage } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
// Create one bash instance per user (reuse across requests)
const userBashInstances = new Map();
async function getBash(userId: string) {
if (!userBashInstances.has(userId)) {
const instance = await createBash({
apiKey: process.env.SUPERMEMORY_API_KEY!,
containerTag: `user_${userId}`,
});
userBashInstances.set(userId, instance);
}
return userBashInstances.get(userId);
}
export async function chat(userId: string, messages: CoreMessage[]) {
const { bash, toolDescription } = await getBash(userId);
return generateText({
model: openai("gpt-4o"),
tools: {
bash: tool({
description: toolDescription,
parameters: z.object({ cmd: z.string() }),
execute: async ({ cmd }) => bash.exec(cmd),
}),
},
maxSteps: 10,
system: `You are a helpful assistant with persistent memory.
Use the bash tool to:
- Read /profile.md at the start of each conversation for context
- Save important facts to /memory.md
- Search with grep when looking for specific information
- Organize notes in subdirectories as needed`,
messages,
});
}
```
## With Vercel AI SDK Streams
For streaming responses in a Next.js app:
```typescript app/api/chat/route.ts
import { createBash } from "@supermemory/bash";
```typescript
import { streamText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";
import { execSync } from "child_process";
export async function POST(req: Request) {
const { messages, userId } = await req.json();
const MEMORY_PATH = "./memory";
const { bash, toolDescription } = await createBash({
apiKey: process.env.SUPERMEMORY_API_KEY!,
containerTag: `user_${userId}`,
});
const result = streamText({
model: anthropic("claude-sonnet-4-20250514"),
tools: {
bash: tool({
description:
"Run a bash command against the memory filesystem at " + MEMORY_PATH,
parameters: z.object({ command: z.string() }),
execute: async ({ command }) => {
try {
return execSync(command, {
cwd: MEMORY_PATH,
encoding: "utf-8",
timeout: 10_000,
});
} catch (e: any) {
return e.stderr || e.message;
}
},
}),
},
maxSteps: 10,
prompt: "Read my memory and summarize what you know about me.",
});
const result = streamText({
model: openai("gpt-4o"),
tools: {
bash: tool({
description: toolDescription,
parameters: z.object({ cmd: z.string() }),
execute: async ({ cmd }) => bash.exec(cmd),
}),
},
maxSteps: 10,
system: "You have persistent memory via the bash tool. Read /profile.md for context.",
messages,
});
return result.toDataStreamResponse();
for await (const chunk of result.textStream) {
process.stdout.write(chunk);
}
```
## Tips
- **One `createBash` per user.** Use the user's ID as the container tag. Each user gets their own isolated memory.
- **Read `profile.md` first.** Tell the model to `cat /profile.md` at the start of each conversation. It's a live digest of everything in the container.
- **`sgrep` for semantic search.** Inside the bash tool, `sgrep "query"` searches by meaning, not just text. Regular `grep` does literal matching.
- **Cache the bash instance.** `createBash` warms the path index on startup. Reuse the instance across requests for the same user.
- **Works with any LLM provider.** Swap `openai("gpt-4o")` for `anthropic("claude-sonnet-4-20250514")`, `google("gemini-2.0-flash")`, or any AI SDK-compatible provider.
## Resources
- [Vercel AI SDK docs](https://sdk.vercel.ai/docs)
- [SMFS Bash Tool reference](/smfs/bash-tool)
- [Supermemory quickstart](/quickstart)
- Mount SMFS once when your server starts, not per-request
- Use `smfs grep 'query'` for semantic search across all files in the container
- Use `--ephemeral` if you don't need a local cache on the server