Skip to content

Commit c01e3a3

Browse files
Prasanna721Dhravyadocs
authored
docs: SMFS documentation — providers, Python bash tool, examples (supermemoryai#889)
Co-authored-by: Dhravya <63950637+Dhravya@users.noreply.github.com> Co-authored-by: docs <docs@supermemory.ai>
1 parent 1c80d43 commit c01e3a3

11 files changed

Lines changed: 2006 additions & 0 deletions

File tree

apps/docs/docs.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,28 @@
144144
"pages": ["supermemory-mcp/claude-desktop"]
145145
}
146146
]
147+
},
148+
{
149+
"anchor": "SMFS",
150+
"icon": "database",
151+
"pages": [
152+
"smfs/overview",
153+
"smfs/install",
154+
"smfs/mount",
155+
"smfs/bash-tool",
156+
"smfs/bash-tool-python",
157+
{
158+
"group": "Providers",
159+
"icon": "cloud",
160+
"pages": [
161+
"smfs/providers/daytona",
162+
"smfs/providers/e2b",
163+
"smfs/providers/vercel",
164+
"smfs/providers/cloudflare"
165+
]
166+
},
167+
"smfs/examples"
168+
]
147169
}
148170
],
149171
"tab": "Developer Platform"
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
---
2+
title: "Bash Tool (Python)"
3+
sidebarTitle: "Bash Tool (Python)"
4+
description: "supermemory-bash. The SMFS idea wrapped as a single agent tool, for Python agents and serverless runtimes."
5+
icon: "terminal"
6+
---
7+
8+
`supermemory-bash` is the SMFS idea wrapped as a single agent tool: `run_bash(command)`. The "filesystem" is your Supermemory container. Runs anywhere Python runs. AWS Lambda, Modal, Fly Machines, Cloud Run, your laptop. No mount, no FUSE, no local disk.
9+
10+
Reach for the Bash Tool when your agent runs somewhere it can't mount a real filesystem.
11+
12+
## Install
13+
14+
```bash
15+
pip install supermemory-bash
16+
```
17+
18+
Or with uv:
19+
20+
```bash
21+
uv add supermemory-bash
22+
```
23+
24+
## Quickstart
25+
26+
```python
27+
import asyncio
28+
import os
29+
from supermemory_bash import create_bash
30+
31+
32+
async def main() -> None:
33+
result = await create_bash(
34+
api_key=os.environ["SUPERMEMORY_API_KEY"],
35+
container_tag="user_42",
36+
)
37+
bash = result.bash
38+
r = await bash.exec("ls /")
39+
print(r.stdout)
40+
41+
42+
asyncio.run(main())
43+
```
44+
45+
`create_bash` returns a `CreateBashResult` with:
46+
47+
- `bash`: a `Shell` instance with `.exec(cmd)`
48+
- `tool_description`: a pre-written tool description ready to hand to the model
49+
- `configure_memory_paths(paths)`: scope which paths get extracted into Supermemory
50+
- `refresh()`: re-prime the path index after external writes
51+
52+
## Use it as a model tool
53+
54+
### Anthropic SDK
55+
56+
Pass `tool_description` straight into Claude's tool definition and run a normal agent loop. Each `tool_use` block calls `bash.exec` and the result goes back as a `tool_result`.
57+
58+
```python
59+
import asyncio
60+
import os
61+
62+
import anthropic
63+
from supermemory_bash import create_bash
64+
65+
66+
async def run_agent(user_message: str) -> str:
67+
result = await create_bash(
68+
api_key=os.environ["SUPERMEMORY_API_KEY"],
69+
container_tag="user_42",
70+
)
71+
bash = result.bash
72+
73+
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
74+
tools = [
75+
{
76+
"name": "bash",
77+
"description": result.tool_description,
78+
"input_schema": {
79+
"type": "object",
80+
"properties": {
81+
"cmd": {"type": "string", "description": "The bash command to run."}
82+
},
83+
"required": ["cmd"],
84+
},
85+
}
86+
]
87+
88+
messages = [{"role": "user", "content": user_message}]
89+
90+
for _ in range(10):
91+
response = client.messages.create(
92+
model="claude-sonnet-4-20250514",
93+
max_tokens=4096,
94+
tools=tools,
95+
messages=messages,
96+
)
97+
98+
if response.stop_reason == "end_turn":
99+
for block in response.content:
100+
if hasattr(block, "text"):
101+
return block.text
102+
return ""
103+
104+
messages.append({"role": "assistant", "content": response.content})
105+
tool_results = []
106+
for block in response.content:
107+
if block.type == "tool_use":
108+
cmd = block.input.get("cmd", "")
109+
r = await bash.exec(cmd)
110+
output = r.stdout
111+
if r.stderr:
112+
output += f"\n[stderr]: {r.stderr}"
113+
if r.exit_code != 0:
114+
output += f"\n[exit_code]: {r.exit_code}"
115+
tool_results.append(
116+
{
117+
"type": "tool_result",
118+
"tool_use_id": block.id,
119+
"content": output or "(no output)",
120+
}
121+
)
122+
messages.append({"role": "user", "content": tool_results})
123+
124+
return "(max steps reached)"
125+
126+
127+
asyncio.run(run_agent("What's in my notes about the Q3 launch?"))
128+
```
129+
130+
### OpenAI SDK
131+
132+
Same idea with OpenAI's function-calling format. Define a single `bash` function, dispatch each `tool_calls` entry to `bash.exec`, and feed the output back as a `tool` message.
133+
134+
```python
135+
import asyncio
136+
import json
137+
import os
138+
139+
from openai import OpenAI
140+
from supermemory_bash import create_bash
141+
142+
143+
async def run_agent(user_message: str) -> str:
144+
result = await create_bash(
145+
api_key=os.environ["SUPERMEMORY_API_KEY"],
146+
container_tag="user_42",
147+
)
148+
bash = result.bash
149+
150+
client = OpenAI()
151+
tools = [
152+
{
153+
"type": "function",
154+
"function": {
155+
"name": "bash",
156+
"description": result.tool_description,
157+
"parameters": {
158+
"type": "object",
159+
"properties": {"cmd": {"type": "string"}},
160+
"required": ["cmd"],
161+
},
162+
},
163+
}
164+
]
165+
166+
messages = [{"role": "user", "content": user_message}]
167+
168+
for _ in range(10):
169+
response = client.chat.completions.create(
170+
model="gpt-4o",
171+
messages=messages,
172+
tools=tools,
173+
)
174+
message = response.choices[0].message
175+
176+
if not message.tool_calls:
177+
return message.content or ""
178+
179+
messages.append(message.model_dump(exclude_none=True))
180+
for call in message.tool_calls:
181+
args = json.loads(call.function.arguments or "{}")
182+
r = await bash.exec(args.get("cmd", ""))
183+
output = r.stdout
184+
if r.stderr:
185+
output += f"\n[stderr]: {r.stderr}"
186+
if r.exit_code != 0:
187+
output += f"\n[exit_code]: {r.exit_code}"
188+
messages.append(
189+
{
190+
"role": "tool",
191+
"tool_call_id": call.id,
192+
"content": output or "(no output)",
193+
}
194+
)
195+
196+
return "(max steps reached)"
197+
198+
199+
asyncio.run(run_agent("List my notes"))
200+
```
201+
202+
### Claude Agent SDK
203+
204+
The [Claude Agent SDK](https://docs.claude.com/en/api/agent-sdk/overview) ships with built-in `Bash`, `Read`, and `Write` tools. If your agent runs somewhere SMFS can be mounted (a long-lived process on macOS or Linux), point those built-ins at an SMFS mount and you don't need `supermemory-bash` at all — the agent just sees your container as a directory.
205+
206+
See [Mount SMFS](/smfs/mount) for setup, or the [provider guides](/smfs/overview#use-smfs-with-your-sandbox-provider) for sandbox-specific instructions.
207+
208+
## Memory
209+
210+
The Bash Tool inherits SMFS memory semantics. By default, files named `user.md` or `memory.md` are extracted as memories. Configure additional memory paths after construction:
211+
212+
```python
213+
result = await create_bash(api_key=api_key, container_tag=container_tag)
214+
bash = result.bash
215+
await result.configure_memory_paths(["/notes/", "/journal.md"])
216+
```
217+
218+
Trailing `/` matches recursively. No slash matches an exact file. Pass `[]` to disable memory generation.
219+
220+
The container also exposes a virtual `profile.md` at the root: a live digest of everything in the container. Read it once at the start of a session to give the model context without walking every file.
221+
222+
```python
223+
r = await bash.exec("cat /profile.md")
224+
print(r.stdout)
225+
```
226+
227+
## Commands the agent can run
228+
229+
The Python tool exposes the same command surface as the TypeScript version: standard Unix builtins (`pwd`, `cd`, `ls`, `cat`, `stat`, `mkdir`, `rm`, `mv`, `cp`, `echo`), search and text utilities (`grep`, `find`, `head`, `tail`, `wc`, `sort`, `sed`, `awk`), plus the custom `sgrep <query> [path]` for semantic search across the container. Pipes, redirects, conditionals, loops, and file tests all work.
230+
231+
See the [TypeScript Bash Tool reference](/smfs/bash-tool#commands-the-agent-can-run) for the full list.
232+
233+
## Configuration
234+
235+
| Option | Default | Purpose |
236+
| --- | --- | --- |
237+
| `api_key` | required | Supermemory API key |
238+
| `container_tag` | required | Container to expose as the filesystem |
239+
| `base_url` | `None` | Override the API endpoint |
240+
| `eager_load` | `True` | Warm the path index when the instance starts |
241+
| `eager_content` | `True` | Also warm the content cache during eager load |
242+
| `cwd` | `"/home/user"` | Initial working directory |
243+
| `env` | `None` | Extra environment variables |
244+
| `cache_ttl_ms` | `150_000` | Content cache TTL in ms. `None` = never expires (single-writer). `0` = no cache. |
245+
246+
The container is what defines the filesystem; setting `cwd` or extra `env` from the host doesn't change the files the agent sees.
247+
248+
## Limitations
249+
250+
- `chmod`, `utimes`, and symlinks (`ln -s`, `readlink`) raise `ENOSYS`.
251+
- `/dev/null` as a redirect target isn't supported. Write to `/tmp/discard.log` instead.
252+
- Binary uploads aren't supported. Text is extracted server-side.

0 commit comments

Comments
 (0)