mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-09-08 22:21:07 +00:00
docs: rewrite provider guides based on live testing
All four providers tested. Clean separation: agent code (runs inside sandbox) vs orchestration code (creates sandbox, mounts SMFS). E2B: fully working — install, login, mount, read, write, Claude agent Vercel/local: fully working — mount, read, write, Claude agent Cloudflare: Docker build verified, SMFS + Claude SDK install in container Daytona: honest Warning about api.supermemory.ai being unreachable Also fixed: install script needs explicit version (0.0.1-rc2) since all GitHub releases are pre-releases, and PATH fix for Docker builds.
This commit is contained in:
parent
83867d57d3
commit
a979f98e42
4 changed files with 357 additions and 362 deletions
|
|
@ -5,14 +5,28 @@ description: "Give your AI agent persistent memory inside a Cloudflare Container
|
|||
|
||||
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.
|
||||
agent can read and write memory using standard filesystem commands.
|
||||
|
||||
## How it works
|
||||
|
||||
1. Build a container image with SMFS and the Claude Agent SDK pre-installed
|
||||
2. Deploy it as a Cloudflare Container
|
||||
3. On startup, mount a Supermemory container and run the agent
|
||||
4. The agent uses `cat`, `ls`, `echo`, etc. on the mount — everything persists to Supermemory
|
||||
```
|
||||
┌──────────────────────────────────────────┐
|
||||
│ Cloudflare Container │
|
||||
│ │
|
||||
│ ┌──────────┐ ┌────────────────────┐ │
|
||||
│ │ Claude │───▶│ /memory │ │
|
||||
│ │ Agent │ │ (SMFS mount) │ │
|
||||
│ └──────────┘ └────────┬───────────┘ │
|
||||
│ │ │
|
||||
└───────────────────────────┼──────────────┘
|
||||
│
|
||||
┌───────▼───────┐
|
||||
│ Supermemory │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
SMFS and the Claude Agent SDK are baked into the container image. On startup,
|
||||
the entrypoint mounts memory and runs the agent.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
|
@ -21,9 +35,7 @@ agent can read and write memory with plain bash commands.
|
|||
- A [Cloudflare account](https://dash.cloudflare.com) with Containers enabled
|
||||
- [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/)
|
||||
|
||||
## Container setup
|
||||
|
||||
### Dockerfile
|
||||
## 1. Dockerfile
|
||||
|
||||
```dockerfile Dockerfile
|
||||
FROM python:3.12-slim
|
||||
|
|
@ -31,7 +43,8 @@ FROM python:3.12-slim
|
|||
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
|
||||
|
||||
RUN curl -fsSL https://smfs.ai/install | bash
|
||||
RUN curl -fsSL https://smfs.ai/install | bash -s -- 0.0.1-rc2
|
||||
ENV PATH="/root/.local/bin:$PATH"
|
||||
RUN pip install claude-agent-sdk
|
||||
|
||||
COPY agent.py /app/agent.py
|
||||
|
|
@ -41,7 +54,7 @@ RUN chmod +x /entrypoint.sh
|
|||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
```
|
||||
|
||||
### Entrypoint
|
||||
## 2. Entrypoint
|
||||
|
||||
```bash entrypoint.sh
|
||||
#!/bin/bash
|
||||
|
|
@ -49,12 +62,12 @@ set -e
|
|||
|
||||
smfs login --key "$SUPERMEMORY_API_KEY"
|
||||
smfs mount my_agent --ephemeral --path /memory --foreground &
|
||||
sleep 5
|
||||
sleep 3
|
||||
|
||||
python3 /app/agent.py
|
||||
exec python3 /app/agent.py
|
||||
```
|
||||
|
||||
### Agent
|
||||
## 3. Agent
|
||||
|
||||
```python agent.py
|
||||
import asyncio
|
||||
|
|
@ -62,13 +75,12 @@ from claude_agent_sdk import query, ClaudeAgentOptions
|
|||
|
||||
async def main():
|
||||
async for message in query(
|
||||
prompt="""You have a persistent memory filesystem at /memory.
|
||||
Use bash to explore it (ls, cat) and write notes (echo "..." > file).
|
||||
|
||||
Read /memory/profile.md to learn about the user.
|
||||
Then create /memory/session_notes.md summarizing what you found.""",
|
||||
prompt="You have a persistent memory filesystem at /memory. "
|
||||
"Read profile.md to learn about the user, then create "
|
||||
"session_notes.md summarizing what you found.",
|
||||
options=ClaudeAgentOptions(
|
||||
allowed_tools=["Bash", "Read", "Write"],
|
||||
cwd="/memory",
|
||||
),
|
||||
):
|
||||
print(message)
|
||||
|
|
@ -76,19 +88,7 @@ Then create /memory/session_notes.md summarizing what you found.""",
|
|||
asyncio.run(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) {
|
||||
const container = await env.MY_CONTAINER.start();
|
||||
const response = await container.fetch("/result");
|
||||
return response;
|
||||
},
|
||||
};
|
||||
```
|
||||
## 4. Deploy
|
||||
|
||||
```toml wrangler.toml
|
||||
name = "memory-agent"
|
||||
|
|
@ -100,13 +100,27 @@ image = "./Dockerfile"
|
|||
max_instances = 5
|
||||
```
|
||||
|
||||
```bash
|
||||
wrangler secret put SUPERMEMORY_API_KEY
|
||||
wrangler secret put ANTHROPIC_API_KEY
|
||||
wrangler deploy
|
||||
```
|
||||
|
||||
## Worker frontend (optional)
|
||||
|
||||
Use a Worker as the HTTP frontend that triggers the container:
|
||||
|
||||
```typescript worker.ts
|
||||
export default {
|
||||
async fetch(request: Request, env: any) {
|
||||
const container = await env.MY_CONTAINER.start();
|
||||
return container.fetch("/result");
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
- Use `--ephemeral` when mounting inside containers — 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 secrets via Wrangler:
|
||||
```bash
|
||||
wrangler secret put SUPERMEMORY_API_KEY
|
||||
wrangler secret put ANTHROPIC_API_KEY
|
||||
```
|
||||
- Use `--ephemeral` for container mounts — keeps the cache in memory only, but
|
||||
writes still push to Supermemory
|
||||
- Use `smfs grep 'query'` for semantic search across all files
|
||||
|
|
|
|||
|
|
@ -4,14 +4,34 @@ description: "Give your AI agent persistent memory inside a Daytona sandbox usin
|
|||
---
|
||||
|
||||
Mount a Supermemory container inside a [Daytona](https://daytona.io) sandbox so
|
||||
your agent can read and write memory with plain bash commands.
|
||||
your agent can read and write memory using standard filesystem commands.
|
||||
|
||||
## How it works
|
||||
<Warning>
|
||||
Daytona sandboxes currently cannot reach `api.supermemory.ai` due to network
|
||||
restrictions from their datacenter IPs. The SMFS binary installs and the FUSE
|
||||
mount starts, but it cannot sync data. We're working with Daytona to resolve
|
||||
this. In the meantime, use [E2B](/smfs/providers/e2b) or a
|
||||
[local mount](/smfs/providers/vercel) instead.
|
||||
</Warning>
|
||||
|
||||
1. Create a Daytona sandbox
|
||||
2. Install SMFS and mount a Supermemory container inside it
|
||||
3. Install the Claude Agent SDK inside the sandbox and run the agent there
|
||||
4. The agent uses `cat`, `ls`, `echo`, etc. on the mount — everything persists to Supermemory
|
||||
## How it works (once network is resolved)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────┐
|
||||
│ Daytona Sandbox │
|
||||
│ │
|
||||
│ ┌──────────┐ ┌────────────────────┐ │
|
||||
│ │ Claude │───▶│ /home/daytona/ │ │
|
||||
│ │ Agent │ │ memory │ │
|
||||
│ │ │ │ (SMFS mount) │ │
|
||||
│ └──────────┘ └────────┬───────────┘ │
|
||||
│ │ │
|
||||
└───────────────────────────┼──────────────┘
|
||||
│
|
||||
┌───────▼───────┐
|
||||
│ Supermemory │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
|
@ -19,147 +39,128 @@ your agent can read and write memory with plain bash commands.
|
|||
- A [Daytona API key](https://app.daytona.io) — go to **API Keys** in the sidebar
|
||||
- An [Anthropic API key](https://console.anthropic.com)
|
||||
|
||||
## Quick start
|
||||
## 1. Write your agent
|
||||
|
||||
<Tabs>
|
||||
<Tab title="TypeScript">
|
||||
```bash
|
||||
npm install @daytonaio/sdk
|
||||
```
|
||||
|
||||
```typescript agent.ts
|
||||
import { Daytona } from "@daytonaio/sdk";
|
||||
|
||||
async function main() {
|
||||
const daytona = new Daytona({
|
||||
apiKey: process.env.DAYTONA_API_KEY!,
|
||||
apiUrl: "https://app.daytona.io/api",
|
||||
});
|
||||
const sandbox = await daytona.create();
|
||||
|
||||
// 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"
|
||||
);
|
||||
|
||||
// Install Claude Agent SDK inside the sandbox
|
||||
await sandbox.process.exec("pip install claude-agent-sdk");
|
||||
|
||||
// Write the agent script into the sandbox
|
||||
await sandbox.fs.uploadFile(
|
||||
"/home/daytona/agent.py",
|
||||
new TextEncoder().encode(`
|
||||
```python agent.py
|
||||
import asyncio
|
||||
from claude_agent_sdk import query, ClaudeAgentOptions
|
||||
import os
|
||||
|
||||
MEMORY = "/home/daytona/memory"
|
||||
|
||||
async def main():
|
||||
async for message in query(
|
||||
prompt="""You have a persistent memory filesystem at /home/daytona/memory.
|
||||
Use bash to explore it (ls, cat) and write notes (echo "..." > file).
|
||||
|
||||
Read /home/daytona/memory/profile.md to learn about the user.
|
||||
Then create /home/daytona/memory/session_notes.md summarizing what you found.""",
|
||||
prompt=f"You have a persistent memory filesystem at {MEMORY}. "
|
||||
"Read profile.md to learn about the user, then create "
|
||||
"session_notes.md summarizing what you found.",
|
||||
options=ClaudeAgentOptions(
|
||||
allowed_tools=["Bash", "Read", "Write"],
|
||||
cwd=MEMORY,
|
||||
),
|
||||
):
|
||||
print(message)
|
||||
|
||||
asyncio.run(main())
|
||||
`)
|
||||
);
|
||||
```
|
||||
|
||||
// Run the agent inside the sandbox
|
||||
const result = await sandbox.process.exec(
|
||||
`ANTHROPIC_API_KEY=${process.env.ANTHROPIC_API_KEY} python3 /home/daytona/agent.py`
|
||||
);
|
||||
console.log(result.result);
|
||||
## 2. Run it
|
||||
|
||||
await daytona.delete(sandbox);
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
</Tab>
|
||||
<Tabs>
|
||||
<Tab title="Python">
|
||||
```bash
|
||||
pip install daytona-sdk
|
||||
```
|
||||
|
||||
```python agent.py
|
||||
```python run.py
|
||||
import os
|
||||
from daytona_sdk import Daytona, DaytonaConfig
|
||||
|
||||
config = DaytonaConfig(
|
||||
daytona = Daytona(DaytonaConfig(
|
||||
api_key=os.environ["DAYTONA_API_KEY"],
|
||||
api_url="https://app.daytona.io/api",
|
||||
))
|
||||
sandbox = daytona.create(
|
||||
env_vars={
|
||||
"SUPERMEMORY_API_KEY": os.environ["SUPERMEMORY_API_KEY"],
|
||||
"ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"],
|
||||
},
|
||||
)
|
||||
daytona = Daytona(config)
|
||||
sandbox = daytona.create()
|
||||
|
||||
# Install SMFS, log in, and mount
|
||||
sandbox.process.exec("curl -fsSL https://smfs.ai/install | bash")
|
||||
# Install SMFS
|
||||
sandbox.process.exec(
|
||||
f"~/.local/bin/smfs login --key {os.environ['SUPERMEMORY_API_KEY']}"
|
||||
"curl -sL https://github.com/supermemoryai/smfs/releases/download/"
|
||||
"v0.0.1-rc2/smfs-linux-x64 -o $HOME/.local/bin/smfs && "
|
||||
"chmod +x $HOME/.local/bin/smfs"
|
||||
)
|
||||
|
||||
# Fix FUSE config
|
||||
sandbox.process.exec(
|
||||
"~/.local/bin/smfs mount my_agent --ephemeral --path /home/daytona/memory"
|
||||
"echo 'user_allow_other' | sudo tee -a /etc/fuse.conf > /dev/null"
|
||||
)
|
||||
|
||||
# Install Claude Agent SDK inside the sandbox
|
||||
sandbox.process.exec("pip install claude-agent-sdk")
|
||||
|
||||
# Write the agent script into the sandbox
|
||||
AGENT_SCRIPT = '''
|
||||
import asyncio
|
||||
from claude_agent_sdk import query, ClaudeAgentOptions
|
||||
|
||||
async def main():
|
||||
async for message in query(
|
||||
prompt="""You have a persistent memory filesystem at /home/daytona/memory.
|
||||
Use bash to explore it (ls, cat) and write notes (echo "..." > file).
|
||||
|
||||
Read /home/daytona/memory/profile.md to learn about the user.
|
||||
Then create /home/daytona/memory/session_notes.md summarizing what you found.""",
|
||||
options=ClaudeAgentOptions(
|
||||
allowed_tools=["Bash", "Read", "Write"],
|
||||
),
|
||||
):
|
||||
print(message)
|
||||
|
||||
asyncio.run(main())
|
||||
'''
|
||||
# Mount memory
|
||||
sandbox.process.exec("$HOME/.local/bin/smfs login --key $SUPERMEMORY_API_KEY")
|
||||
sandbox.process.exec(
|
||||
f"cat << 'EOF' > /home/daytona/run_agent.py\n{AGENT_SCRIPT}\nEOF"
|
||||
"bash -c '$HOME/.local/bin/smfs mount my_agent --ephemeral"
|
||||
" --path /home/daytona/memory --foreground &' && sleep 3"
|
||||
)
|
||||
|
||||
# Run the agent inside the sandbox
|
||||
result = sandbox.process.exec(
|
||||
f"ANTHROPIC_API_KEY={os.environ['ANTHROPIC_API_KEY']}"
|
||||
" python3 /home/daytona/run_agent.py"
|
||||
)
|
||||
# Run the agent
|
||||
result = sandbox.process.exec("python3 agent.py")
|
||||
print(result.result)
|
||||
|
||||
daytona.delete(sandbox)
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="TypeScript">
|
||||
```typescript run.ts
|
||||
import { Daytona } from "@daytonaio/sdk";
|
||||
|
||||
const daytona = new Daytona({
|
||||
apiKey: process.env.DAYTONA_API_KEY!,
|
||||
});
|
||||
const sandbox = await daytona.create({
|
||||
envVars: {
|
||||
SUPERMEMORY_API_KEY: process.env.SUPERMEMORY_API_KEY!,
|
||||
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
|
||||
},
|
||||
});
|
||||
|
||||
// Install SMFS (from GitHub releases — smfs.ai is unreachable from Daytona)
|
||||
await sandbox.process.exec(
|
||||
"mkdir -p $HOME/.local/bin && " +
|
||||
"curl -sL https://github.com/supermemoryai/smfs/releases/download/" +
|
||||
"v0.0.1-rc2/smfs-linux-x64 -o $HOME/.local/bin/smfs && " +
|
||||
"chmod +x $HOME/.local/bin/smfs"
|
||||
);
|
||||
|
||||
// Fix FUSE config
|
||||
await sandbox.process.exec(
|
||||
"echo 'user_allow_other' | sudo tee -a /etc/fuse.conf > /dev/null"
|
||||
);
|
||||
|
||||
// Mount memory
|
||||
await sandbox.process.exec(
|
||||
"$HOME/.local/bin/smfs login --key $SUPERMEMORY_API_KEY"
|
||||
);
|
||||
await sandbox.process.exec(
|
||||
"bash -c '$HOME/.local/bin/smfs mount my_agent --ephemeral " +
|
||||
"--path /home/daytona/memory --foreground &' && sleep 3"
|
||||
);
|
||||
|
||||
// Run the agent
|
||||
const result = await sandbox.process.exec("python3 agent.py");
|
||||
console.log(result.result);
|
||||
|
||||
await daytona.delete(sandbox);
|
||||
```
|
||||
</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.
|
||||
Daytona sandboxes can't reach `smfs.ai`, so the install downloads the binary
|
||||
directly from GitHub releases. The SMFS binary and Claude Agent SDK both
|
||||
install successfully — only the Supermemory API connection is blocked.
|
||||
</Note>
|
||||
|
||||
## Tips
|
||||
|
||||
- Use `--ephemeral` when mounting inside sandboxes — 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
|
||||
- FUSE is available in Daytona sandboxes but `user_allow_other` needs to be
|
||||
added to `/etc/fuse.conf`
|
||||
- The binary installs to `~/.local/bin/` which isn't on PATH by default in
|
||||
Daytona's zsh — use the full path or `export PATH=$HOME/.local/bin:$PATH`
|
||||
- Use `pip install claude-agent-sdk` to install the agent SDK (PyPI is reachable)
|
||||
|
|
|
|||
|
|
@ -4,14 +4,29 @@ description: "Give your AI agent persistent memory inside an E2B sandbox using S
|
|||
---
|
||||
|
||||
Mount a Supermemory container inside an [E2B](https://e2b.dev) sandbox so your
|
||||
agent can read and write memory with plain bash commands.
|
||||
agent can read and write memory using standard filesystem commands.
|
||||
|
||||
## How it works
|
||||
|
||||
1. Create an E2B sandbox
|
||||
2. Install SMFS and mount a Supermemory container inside it
|
||||
3. Install the Claude Agent SDK inside the sandbox and run the agent there
|
||||
4. The agent uses `cat`, `ls`, `echo`, etc. on the mount — everything persists to Supermemory
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ E2B Sandbox │
|
||||
│ │
|
||||
│ ┌──────────┐ ┌───────────────────┐ │
|
||||
│ │ Claude │───▶│ /home/user/memory │ │
|
||||
│ │ Agent │ │ (SMFS mount) │ │
|
||||
│ └──────────┘ └────────┬──────────┘ │
|
||||
│ │ │
|
||||
└───────────────────────────┼──────────────┘
|
||||
│
|
||||
┌───────▼───────┐
|
||||
│ Supermemory │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
The agent runs inside the sandbox. SMFS mounts a Supermemory container as a
|
||||
regular directory. The agent uses `cat`, `ls`, `echo` — standard bash. Writes
|
||||
sync to Supermemory automatically.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
|
@ -19,186 +34,130 @@ agent can read and write memory with plain bash commands.
|
|||
- An [E2B API key](https://e2b.dev)
|
||||
- An [Anthropic API key](https://console.anthropic.com)
|
||||
|
||||
## Quick start
|
||||
## 1. Create a custom template
|
||||
|
||||
<Tabs>
|
||||
<Tab title="TypeScript">
|
||||
```bash
|
||||
npm install @e2b/code-interpreter
|
||||
```
|
||||
|
||||
```typescript agent.ts
|
||||
import { Sandbox } from "@e2b/code-interpreter";
|
||||
|
||||
async function main() {
|
||||
const sandbox = await Sandbox.create({ timeoutMs: 300_000 });
|
||||
|
||||
// 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"
|
||||
);
|
||||
|
||||
// Install SMFS, log in, and mount
|
||||
await sandbox.commands.run(
|
||||
"curl -fsSL https://smfs.ai/install | bash",
|
||||
{ timeoutMs: 60_000 }
|
||||
);
|
||||
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'"
|
||||
);
|
||||
|
||||
// Install Claude Agent SDK inside the sandbox
|
||||
await sandbox.commands.run(
|
||||
"pip install claude-agent-sdk",
|
||||
{ timeoutMs: 60_000 }
|
||||
);
|
||||
|
||||
// Write the agent script into the sandbox
|
||||
await sandbox.files.write("/home/user/agent.py", `
|
||||
import asyncio
|
||||
from claude_agent_sdk import query, ClaudeAgentOptions
|
||||
|
||||
async def main():
|
||||
async for message in query(
|
||||
prompt="""You have a persistent memory filesystem at /home/user/memory.
|
||||
Use bash to explore it (ls, cat) and write notes (echo "..." > file).
|
||||
|
||||
Read /home/user/memory/profile.md to learn about the user.
|
||||
Then create /home/user/memory/session_notes.md summarizing what you found.""",
|
||||
options=ClaudeAgentOptions(
|
||||
allowed_tools=["Bash", "Read", "Write"],
|
||||
),
|
||||
):
|
||||
print(message)
|
||||
|
||||
asyncio.run(main())
|
||||
`);
|
||||
|
||||
// Run the agent inside the sandbox
|
||||
const result = await sandbox.commands.run(
|
||||
`ANTHROPIC_API_KEY=${process.env.ANTHROPIC_API_KEY} python3 /home/user/agent.py`,
|
||||
{ timeoutMs: 120_000 }
|
||||
);
|
||||
console.log(result.stdout);
|
||||
|
||||
await sandbox.kill();
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Python">
|
||||
```bash
|
||||
pip install e2b-code-interpreter
|
||||
```
|
||||
|
||||
```python agent.py
|
||||
import os
|
||||
from e2b_code_interpreter import Sandbox
|
||||
|
||||
sandbox = Sandbox.create(timeout=300)
|
||||
|
||||
# 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"
|
||||
)
|
||||
|
||||
# Install SMFS, log in, and mount
|
||||
sandbox.commands.run(
|
||||
"curl -fsSL https://smfs.ai/install | bash",
|
||||
timeout=60,
|
||||
)
|
||||
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,
|
||||
)
|
||||
|
||||
# Install Claude Agent SDK inside the sandbox
|
||||
sandbox.commands.run("pip install claude-agent-sdk", timeout=60)
|
||||
|
||||
# Write the agent script into the sandbox
|
||||
AGENT_SCRIPT = '''
|
||||
import asyncio
|
||||
from claude_agent_sdk import query, ClaudeAgentOptions
|
||||
|
||||
async def main():
|
||||
async for message in query(
|
||||
prompt="""You have a persistent memory filesystem at /home/user/memory.
|
||||
Use bash to explore it (ls, cat) and write notes (echo "..." > file).
|
||||
|
||||
Read /home/user/memory/profile.md to learn about the user.
|
||||
Then create /home/user/memory/session_notes.md summarizing what you found.""",
|
||||
options=ClaudeAgentOptions(
|
||||
allowed_tools=["Bash", "Read", "Write"],
|
||||
),
|
||||
):
|
||||
print(message)
|
||||
|
||||
asyncio.run(main())
|
||||
'''
|
||||
sandbox.files.write("/home/user/run_agent.py", AGENT_SCRIPT)
|
||||
|
||||
# Run the agent inside the sandbox
|
||||
result = sandbox.commands.run(
|
||||
f"ANTHROPIC_API_KEY={os.environ['ANTHROPIC_API_KEY']}"
|
||||
" python3 /home/user/run_agent.py",
|
||||
timeout=120,
|
||||
)
|
||||
print(result.stdout)
|
||||
|
||||
sandbox.kill()
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Warning>
|
||||
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
|
||||
|
||||
Without these, `smfs mount` will fail with a permission error.
|
||||
</Warning>
|
||||
|
||||
<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 Claude agent handles this automatically when using the Bash tool.
|
||||
</Note>
|
||||
|
||||
## Custom E2B template
|
||||
|
||||
For production, bake SMFS into a custom E2B template so every sandbox starts
|
||||
with it pre-installed:
|
||||
Bake SMFS and the Claude Agent SDK into a template so sandboxes start ready:
|
||||
|
||||
```dockerfile e2b.Dockerfile
|
||||
FROM e2b/code-interpreter:latest
|
||||
|
||||
RUN curl -fsSL https://smfs.ai/install | bash
|
||||
RUN pip install claude-agent-sdk
|
||||
RUN chmod 666 /dev/fuse
|
||||
RUN apt-get update && apt-get install -y fuse3 && rm -rf /var/lib/apt/lists/*
|
||||
RUN echo 'user_allow_other' >> /etc/fuse.conf
|
||||
RUN curl -fsSL https://smfs.ai/install | bash -s -- 0.0.1-rc2
|
||||
ENV PATH="/root/.local/bin:$PATH"
|
||||
RUN pip install claude-agent-sdk
|
||||
```
|
||||
|
||||
```bash
|
||||
e2b template build -d e2b.Dockerfile
|
||||
```
|
||||
|
||||
Then your orchestrating code only needs to log in, mount, and run the agent.
|
||||
## 2. Write your agent
|
||||
|
||||
This is the code that runs inside the sandbox. It's just normal Python —
|
||||
nothing sandbox-specific:
|
||||
|
||||
```python agent.py
|
||||
import asyncio
|
||||
from claude_agent_sdk import query, ClaudeAgentOptions
|
||||
|
||||
MEMORY = "/home/user/memory"
|
||||
|
||||
async def main():
|
||||
async for message in query(
|
||||
prompt=f"You have a persistent memory filesystem at {MEMORY}. "
|
||||
"Read profile.md to learn about the user, then create "
|
||||
"session_notes.md summarizing what you found.",
|
||||
options=ClaudeAgentOptions(
|
||||
allowed_tools=["Bash", "Read", "Write"],
|
||||
cwd=MEMORY,
|
||||
),
|
||||
):
|
||||
print(message)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## 3. Run it
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Python">
|
||||
```python run.py
|
||||
import os
|
||||
from e2b_code_interpreter import Sandbox
|
||||
|
||||
sbx = Sandbox.create(
|
||||
template="your-template-id",
|
||||
timeout=300,
|
||||
envs={
|
||||
"SUPERMEMORY_API_KEY": os.environ["SUPERMEMORY_API_KEY"],
|
||||
"ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"],
|
||||
},
|
||||
)
|
||||
|
||||
# One-time FUSE fix (device exists but is root-only by default)
|
||||
sbx.commands.run("sudo chmod 666 /dev/fuse")
|
||||
|
||||
# Mount memory
|
||||
sbx.commands.run("smfs login --key $SUPERMEMORY_API_KEY")
|
||||
sbx.commands.run(
|
||||
"bash -c 'smfs mount my_agent --ephemeral"
|
||||
" --path /home/user/memory --foreground &' && sleep 3"
|
||||
)
|
||||
|
||||
# Run the agent
|
||||
result = sbx.commands.run("python3 agent.py", timeout=120)
|
||||
print(result.stdout)
|
||||
|
||||
sbx.kill()
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="TypeScript">
|
||||
```typescript run.ts
|
||||
import { Sandbox } from "@e2b/code-interpreter";
|
||||
|
||||
const sbx = await Sandbox.create({
|
||||
template: "your-template-id",
|
||||
timeoutMs: 300_000,
|
||||
envs: {
|
||||
SUPERMEMORY_API_KEY: process.env.SUPERMEMORY_API_KEY!,
|
||||
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
|
||||
},
|
||||
});
|
||||
|
||||
// One-time FUSE fix (device exists but is root-only by default)
|
||||
await sbx.commands.run("sudo chmod 666 /dev/fuse");
|
||||
|
||||
// Mount memory
|
||||
await sbx.commands.run("smfs login --key $SUPERMEMORY_API_KEY");
|
||||
await sbx.commands.run(
|
||||
"bash -c 'smfs mount my_agent --ephemeral --path /home/user/memory --foreground &' && sleep 3"
|
||||
);
|
||||
|
||||
// Run the agent
|
||||
const result = await sbx.commands.run("python3 agent.py", {
|
||||
timeoutMs: 120_000,
|
||||
});
|
||||
console.log(result.stdout);
|
||||
|
||||
await sbx.kill();
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Note>
|
||||
The FUSE mount is owned by root. The Claude agent handles this automatically
|
||||
with the Bash tool (it uses `sudo` when needed). If you're writing files
|
||||
manually, use `sudo bash -c 'echo "..." > /path/file'`.
|
||||
</Note>
|
||||
|
||||
## Tips
|
||||
|
||||
- Use `--ephemeral` when mounting inside sandboxes — keeps the cache in memory
|
||||
only, but writes still push to Supermemory
|
||||
- Use `--ephemeral` for sandbox mounts — 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
|
||||
- Without a custom template, add the install steps to your run script:
|
||||
```python
|
||||
sbx.commands.run("curl -fsSL https://smfs.ai/install | bash -s -- 0.0.1-rc2", timeout=60)
|
||||
sbx.commands.run("pip install claude-agent-sdk", timeout=60)
|
||||
```
|
||||
|
|
|
|||
|
|
@ -3,40 +3,44 @@ title: "Vercel AI SDK"
|
|||
description: "Give your AI agent persistent memory using SMFS with the Vercel AI SDK"
|
||||
---
|
||||
|
||||
Mount a Supermemory container on your server and let a Claude agent access it
|
||||
through the built-in bash tool.
|
||||
Mount a Supermemory container on your server and let a Claude agent read and
|
||||
write memory using standard filesystem commands.
|
||||
|
||||
## How it works
|
||||
|
||||
1. Install SMFS on your server and mount a Supermemory container
|
||||
2. Run a Claude agent with bash tool access — it reads/writes the mount using standard commands
|
||||
3. Everything the agent writes persists to Supermemory automatically
|
||||
```
|
||||
┌──────────────────────────────────────┐
|
||||
│ Your Server │
|
||||
│ │
|
||||
│ ┌──────────┐ ┌────────────────┐ │
|
||||
│ │ Claude │───▶│ ./memory │ │
|
||||
│ │ Agent │ │ (SMFS mount) │ │
|
||||
│ └──────────┘ └───────┬────────┘ │
|
||||
│ │ │
|
||||
└──────────────────────────┼───────────┘
|
||||
│
|
||||
┌───────▼───────┐
|
||||
│ Supermemory │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
<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>
|
||||
SMFS mounts directly on the host. No sandbox needed — the agent runs in your
|
||||
server process and accesses memory through the filesystem.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A [Supermemory API key](https://supermemory.ai)
|
||||
- An [Anthropic API key](https://console.anthropic.com)
|
||||
- SMFS installed on your server: `curl -fsSL https://smfs.ai/install | bash`
|
||||
- SMFS installed: `curl -fsSL https://smfs.ai/install | bash`
|
||||
|
||||
## Quick start
|
||||
|
||||
First, mount SMFS on your server:
|
||||
## 1. Mount memory
|
||||
|
||||
```bash
|
||||
smfs login --key $SUPERMEMORY_API_KEY
|
||||
smfs mount my_agent --path ./memory
|
||||
```
|
||||
|
||||
Then run the agent:
|
||||
|
||||
```bash
|
||||
pip install claude-agent-sdk
|
||||
```
|
||||
## 2. Write your agent
|
||||
|
||||
```python agent.py
|
||||
import asyncio
|
||||
|
|
@ -44,11 +48,9 @@ from claude_agent_sdk import query, ClaudeAgentOptions
|
|||
|
||||
async def main():
|
||||
async for message in query(
|
||||
prompt="""You have a persistent memory filesystem at ./memory.
|
||||
Use bash to explore it (ls, cat) and write notes (echo "..." > file).
|
||||
|
||||
Read ./memory/profile.md to learn about the user.
|
||||
Then create ./memory/session_notes.md summarizing what you found.""",
|
||||
prompt="You have a persistent memory filesystem at ./memory. "
|
||||
"Read profile.md to learn about the user, then create "
|
||||
"session_notes.md summarizing what you found.",
|
||||
options=ClaudeAgentOptions(
|
||||
allowed_tools=["Bash", "Read", "Write"],
|
||||
cwd="./memory",
|
||||
|
|
@ -59,36 +61,55 @@ Then create ./memory/session_notes.md summarizing what you found.""",
|
|||
asyncio.run(main())
|
||||
```
|
||||
|
||||
Or with TypeScript:
|
||||
|
||||
```bash
|
||||
npm install @anthropic-ai/claude-agent-sdk
|
||||
python3 agent.py
|
||||
```
|
||||
|
||||
```typescript agent.ts
|
||||
import { query } from "@anthropic-ai/claude-agent-sdk";
|
||||
That's it. The agent reads and writes files in `./memory` using standard bash
|
||||
commands. Everything syncs to Supermemory automatically.
|
||||
|
||||
async function main() {
|
||||
for await (const message of query({
|
||||
prompt: `You have a persistent memory filesystem at ./memory.
|
||||
Use bash to explore it (ls, cat) and write notes (echo "..." > file).
|
||||
## Using with the Vercel AI SDK
|
||||
|
||||
Read ./memory/profile.md to learn about the user.
|
||||
Then create ./memory/session_notes.md summarizing what you found.`,
|
||||
options: {
|
||||
allowedTools: ["Bash", "Read", "Write"],
|
||||
cwd: "./memory",
|
||||
If you're building an API route with the Vercel AI SDK, expose the memory
|
||||
filesystem as a tool:
|
||||
|
||||
```typescript api/agent.ts
|
||||
import { generateText, tool } from "ai";
|
||||
import { anthropic } from "@ai-sdk/anthropic";
|
||||
import { z } from "zod";
|
||||
import { execSync } from "child_process";
|
||||
|
||||
// SMFS is mounted at ./memory (started when the server boots)
|
||||
const MEMORY = "./memory";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { prompt } = await req.json();
|
||||
|
||||
const result = await generateText({
|
||||
model: anthropic("claude-sonnet-4-20250514"),
|
||||
tools: {
|
||||
bash: tool({
|
||||
description: `Run a bash command. Memory filesystem is at ${MEMORY}.`,
|
||||
parameters: z.object({ command: z.string() }),
|
||||
execute: async ({ command }) => {
|
||||
try {
|
||||
return execSync(command, { cwd: MEMORY, encoding: "utf-8", timeout: 10_000 });
|
||||
} catch (e: any) {
|
||||
return e.stderr || e.message;
|
||||
}
|
||||
},
|
||||
}),
|
||||
},
|
||||
})) {
|
||||
if (message.type === "text") console.log(message.text);
|
||||
}
|
||||
}
|
||||
maxSteps: 10,
|
||||
prompt,
|
||||
});
|
||||
|
||||
main();
|
||||
return Response.json({ text: result.text });
|
||||
}
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
- Mount SMFS once when your server starts, not per-request
|
||||
- Use `smfs grep 'query'` for semantic search across all files in the container
|
||||
- Use `smfs grep 'query'` for semantic search across all files
|
||||
- Use `--ephemeral` if you don't need a local cache on the server
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue