diff --git a/apps/docs/smfs/providers/cloudflare.mdx b/apps/docs/smfs/providers/cloudflare.mdx index e1575b4e..f6e04d0b 100644 --- a/apps/docs/smfs/providers/cloudflare.mdx +++ b/apps/docs/smfs/providers/cloudflare.mdx @@ -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 diff --git a/apps/docs/smfs/providers/daytona.mdx b/apps/docs/smfs/providers/daytona.mdx index 7e50bd7d..482061b0 100644 --- a/apps/docs/smfs/providers/daytona.mdx +++ b/apps/docs/smfs/providers/daytona.mdx @@ -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 + + 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. + -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 - - - ```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(); - ``` - + - ```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) ``` + + ```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); + ``` + - 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. ## 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) diff --git a/apps/docs/smfs/providers/e2b.mdx b/apps/docs/smfs/providers/e2b.mdx index 7dd1bf8d..3c719686 100644 --- a/apps/docs/smfs/providers/e2b.mdx +++ b/apps/docs/smfs/providers/e2b.mdx @@ -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 - - - ```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(); - ``` - - - ```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() - ``` - - - - - 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. - - - - 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. - - -## 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 + + + + ```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() + ``` + + + ```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(); + ``` + + + + + 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'`. + ## 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) + ``` diff --git a/apps/docs/smfs/providers/vercel.mdx b/apps/docs/smfs/providers/vercel.mdx index aa6dca6b..b1c7daab 100644 --- a/apps/docs/smfs/providers/vercel.mdx +++ b/apps/docs/smfs/providers/vercel.mdx @@ -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 │ + └───────────────┘ +``` - - The Vercel AI SDK runs in your server process (not in a sandbox). SMFS mounts - directly on the host where your server runs. - +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