diff --git a/apps/docs/docs.json b/apps/docs/docs.json index 5731c945..c385883f 100644 --- a/apps/docs/docs.json +++ b/apps/docs/docs.json @@ -144,6 +144,16 @@ "pages": ["supermemory-mcp/claude-desktop"] } ] + }, + { + "anchor": "SMFS", + "icon": "database", + "pages": [ + "smfs/overview", + "smfs/install", + "smfs/mount", + "smfs/bash-tool" + ] } ], "tab": "Developer Platform" diff --git a/apps/docs/smfs/bash-tool.mdx b/apps/docs/smfs/bash-tool.mdx new file mode 100644 index 00000000..19aadd60 --- /dev/null +++ b/apps/docs/smfs/bash-tool.mdx @@ -0,0 +1,203 @@ +--- +title: "Bash Tool" +sidebarTitle: "Bash Tool" +description: "@supermemory/bash. The SMFS idea wrapped as a single agent tool, for serverless and edge runtimes." +icon: "terminal" +--- + +`@supermemory/bash` is the SMFS idea wrapped as a single agent tool: `run_bash(command)`. The "filesystem" is your Supermemory container. Runs anywhere TypeScript runs. Cloudflare Workers, AWS Lambda, Vercel, Node, the browser. No mount, no FUSE, no local disk. + +Reach for the Bash Tool when your agent runs somewhere it can't mount a real filesystem. + +## Install + +```bash +npm install @supermemory/bash +``` + +Or with bun: + +```bash +bun add @supermemory/bash +``` + +## Quickstart + +```typescript +import { createBash } from "@supermemory/bash"; + +const { bash, toolDescription } = await createBash({ + apiKey: process.env.SUPERMEMORY_API_KEY!, + containerTag: "user_42", +}); + +const result = await bash.exec("ls /"); +console.log(result.stdout); +``` + +`createBash` returns: + +- `bash`: the instance with `.exec(cmd)` +- `toolDescription`: a pre-written tool description ready to hand to the model +- `configureMemoryPaths(paths)`: scope which paths get extracted into Supermemory +- `refresh()`: re-prime the path index after external writes + +## Use it as a model tool + +### Vercel AI SDK + +```typescript +import { generateText, tool } from "ai"; +import { openai } from "@ai-sdk/openai"; +import { z } from "zod"; + +const { bash, toolDescription } = await createBash({ + apiKey: process.env.SUPERMEMORY_API_KEY!, + containerTag: "user_42", +}); + +const result = await generateText({ + model: openai("gpt-4o"), + tools: { + bash: tool({ + description: toolDescription, + inputSchema: z.object({ cmd: z.string() }), + execute: async ({ cmd }) => bash.exec(cmd), + }), + }, + prompt: "What's in my notes about the Q3 launch?", +}); +``` + +### Anthropic SDK + +```typescript +import Anthropic from "@anthropic-ai/sdk"; + +const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! }); +const { bash, toolDescription } = await createBash({ + apiKey: process.env.SUPERMEMORY_API_KEY!, + containerTag: "user_42", +}); + +const response = await client.messages.create({ + model: "claude-opus-4-7", + max_tokens: 4096, + tools: [ + { + name: "bash", + description: toolDescription, + input_schema: { + type: "object", + properties: { cmd: { type: "string" } }, + required: ["cmd"], + }, + }, + ], + messages: [{ role: "user", content: "List my notes" }], +}); +``` + +### OpenAI SDK + +```typescript +import OpenAI from "openai"; + +const client = new OpenAI(); +const { bash, toolDescription } = await createBash({ + apiKey: process.env.SUPERMEMORY_API_KEY!, + containerTag: "user_42", +}); + +const response = await client.chat.completions.create({ + model: "gpt-4o", + messages: [{ role: "user", content: "List my notes" }], + tools: [ + { + type: "function", + function: { + name: "bash", + description: toolDescription, + parameters: { + type: "object", + properties: { cmd: { type: "string" } }, + required: ["cmd"], + }, + }, + }, + ], +}); +``` + +## Memory + +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: + +```typescript +const { configureMemoryPaths } = await createBash({ apiKey, containerTag }); + +await configureMemoryPaths(["/notes/", "/journal.md"]); +``` + +Trailing `/` matches recursively. No slash matches an exact file. Pass `[]` to disable memory generation. + +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. + +```typescript +const { stdout } = await bash.exec("cat /profile.md"); +``` + +## Commands the agent can run + +Standard Unix surface, plus one custom command. Each does what you'd expect. + +### Filesystem + +- `pwd`: print working directory +- `cd`: change directory +- `ls`, `ls -la`: list +- `cat`: read a file +- `stat`: file metadata +- `mkdir`: create directory +- `rm`, `rm -rf`: delete +- `rmdir`: delete empty directory +- `mv`: move or rename +- `cp`: copy +- `echo`: write or append (`echo "x" > file`, `echo "x" >> file`) + +### Search and text + +- `grep`: literal substring match against a known path +- `sgrep [path]`: **semantic** search across the container. Trailing `/` on path scopes to a directory. No path searches everything. +- `find`: search by name or properties +- `head`, `tail`: first or last N lines +- `wc`: word, line, byte counts +- `sort`: sort lines +- `sed`, `awk`: text transformation + +### Shell features + +- Pipes (`|`) +- Redirects (`>`, `>>`) +- Conditionals (`&&`, `||`) +- Loops (`for`, `while`) +- File tests (`[ -f ]`, `[ -d ]`, `[ -e ]`) + +## Configuration + +| Option | Default | Purpose | +| --- | --- | --- | +| `apiKey` | required | Supermemory API key | +| `containerTag` | required | Container to expose as the filesystem | +| `baseURL` | SDK default | Override the API endpoint | +| `eagerLoad` | `true` | Warm the path index when the instance starts | +| `eagerContent` | `true` | Also warm the content cache during eager load | +| `cacheTtlMs` | `150_000` | Content cache TTL in ms. `null` = never expires (single-writer). `0` = no cache. | + +Other options (`customCommands`, `logger`, plus `just-bash` pass-throughs like `executionLimits`, `network`, `python`, `javascript`, `cwd`, `env`) exist but aren't part of the supported surface for the SMFS use case. The container is what defines the filesystem; setting `cwd` or extra `env` from the host doesn't change that. + +## Limitations + +- `chmod`, `utimes`, and symlinks (`ln -s`, `readlink`) throw `ENOSYS`. +- `/dev/null` as a redirect target isn't supported. Write to `/tmp/discard.log` instead. +- Binary uploads aren't supported. Text is extracted server-side. diff --git a/apps/docs/smfs/install.mdx b/apps/docs/smfs/install.mdx new file mode 100644 index 00000000..806f7548 --- /dev/null +++ b/apps/docs/smfs/install.mdx @@ -0,0 +1,68 @@ +--- +title: "Install SMFS" +sidebarTitle: "Install" +description: "Install, log in, mount." +icon: "download" +--- + +## 1. Install the binary + +```bash +curl -fsSL smfs.ai/install | sh +``` + +Drops `smfs` into `~/.local/bin`. Works on macOS (arm64, x64) and Linux (arm64, x64). + +If `smfs` isn't on your `PATH` after install, add `~/.local/bin` to your shell profile and reopen the terminal. + +## 2. Log in + +```bash +smfs login +``` + +One-time. Prompts you for your Supermemory API key and stores it in your global credentials. Get a key at [console.supermemory.ai](https://console.supermemory.ai). + +You can also pass the key directly: + +```bash +smfs login --key sm_... +``` + +## 3. Mount a container + +```bash +smfs mount agent_memory +``` + +`agent_memory` is your container tag. SMFS creates a folder named `agent_memory/` in the current directory and mounts the container there. + +That's it. Read it with `ls`, `cat`, `grep`. See [Mount](/smfs/mount) for memory paths, sync modes, flags, and every subcommand. + +To mount somewhere else, pass `--path`: + +```bash +smfs mount agent_memory --path ~/memory +``` + +## Optional: refresh the semantic grep wrapper + +`smfs mount` installs the shell wrapper automatically the first time you mount. If you ever need to force a clean reinstall (after upgrading the binary, for example): + +```bash +smfs init +``` + +It writes the wrapper into your `~/.zshrc` directly. Then reopen your terminal (or `source ~/.zshrc`) so the new shell picks it up. + +Inside any mount, plain `grep` becomes semantic. Outside a mount, your normal `grep` is untouched. Pass any flag (`grep -r`, `grep -i`, anything) and you get the real `grep` back. + +## Refresh the binary + +If anything ever feels broken: + +```bash +smfs install +``` + +Re-copies the binary into `~/.local/bin` and resets permissions. diff --git a/apps/docs/smfs/mount.mdx b/apps/docs/smfs/mount.mdx new file mode 100644 index 00000000..1c31bcb2 --- /dev/null +++ b/apps/docs/smfs/mount.mdx @@ -0,0 +1,289 @@ +--- +title: "Mount" +sidebarTitle: "Mount" +description: "Mount a Supermemory container, generate memories, and sync." +icon: "hard-drive" +--- + +A mount turns a Supermemory container into a directory on your machine. macOS uses NFSv3, Linux uses FUSE. Both are handled for you. + +```bash +smfs mount +``` + +Example: + +```bash +smfs mount agent_memory +``` + +`agent_memory` is the container tag. SMFS creates a folder named `agent_memory/` in the current directory and mounts the container there. The mount runs as a background daemon. A marker file `.smfs` is written at the mount root so other tools (and the semantic `grep` wrapper from `smfs init`) can find the mount. + +To mount at a different path: + +```bash +smfs mount agent_memory --path ~/memory +``` + +## Memory + +This is the part most people miss. SMFS isn't a normal filesystem. It generates **memories** from files at specific paths. Memories are extracted, summarized, and indexed by Supermemory. + +Files outside those paths are still semantically searchable; they're indexed through **SuperRAG** by default. Nothing in the mount is dead weight. + +### Defaults + +By default, files named `user.md` or `memory.md` are treated as memory paths. Drop those files anywhere in your mount and Supermemory generates memories from them automatically. + +### Configure your own memory paths + +Pass `--memory-paths` at mount time to control which files become memories: + +```bash +smfs mount agent_memory --memory-paths "/notes/,/journal.md" +``` + +Rules: + +- Paths are **absolute**, anchored at the mount root. Always start with `/`. +- Trailing `/` matches every file inside that folder, recursively (`/notes/` covers `/notes/foo.md`, `/notes/2026/march.md`, etc.). +- No trailing slash matches one exact file (`/journal.md`). +- Comma-separated. Multiple paths are fine. +- Empty string disables memory generation entirely (`--memory-paths ""`). +- Omit the flag and Supermemory keeps whatever the container tag already has, falling back to `user.md` and `memory.md`. + +### profile.md + +Every mount has a virtual file at the root called `profile.md`. It's auto-generated, read-only, and backed by Supermemory. The model can `cat profile.md` to get a live digest of everything in the container without walking every file. Useful as a first call at the start of a session. + +```bash +cat agent_memory/profile.md +``` + +You can't write to it. As the underlying memories change, Supermemory regenerates it. + +## Sync modes + +Three modes plus a force-sync command. Pick by what your agent actually needs. + +### Bidirectional (default) + +Local reads hit the cache. Local writes queue and push to Supermemory in the background. Remote changes are pulled on a poll. This is what you get if you pass no flags. + +```bash +smfs mount agent_memory +``` + +Use this when more than one writer (you, another agent, the dashboard) might touch the container. + +### No-sync + +Writes still push to Supermemory. Polling for remote changes is off. The agent sees a view that doesn't shift under it mid-task. + +```bash +smfs mount agent_memory --no-sync +``` + +Use this when your agent is the only writer, or when you want predictable reads. + +### Ephemeral + +Cache is in memory only. Nothing persists after unmount. Writes still push. + +```bash +smfs mount agent_memory --ephemeral +``` + +Use this for short-lived sandboxes. CI jobs, throwaway containers, one-shot agent runs. + +### Force a sync now + +```bash +smfs sync +``` + +Pushes pending writes and pulls remote changes immediately. Useful right before tearing down a sandbox. + +## All mount flags + +| Flag | What it does | +| --- | --- | +| `--path ` | Override the default mount path (`.//`). | +| `--memory-paths ` | Scope which files become memories. See [Memory](#memory). | +| `--no-sync` | Stop polling for remote changes. Writes still push. | +| `--clean` | Wipe local cache before mounting. Pulls fresh from the API. | +| `--ephemeral` | In-memory cache. Nothing persists after unmount. | +| `--sync-interval ` | Remote-change poll interval. Default `30`. | +| `--drain-timeout ` | Max time to flush pending writes during unmount. Default `30`. | +| `--foreground` | Run the daemon inline instead of detaching. | +| `--backend ` | Linux only. `fuse` (default) or `nfs`. | +| `--key ` | Pass an API key explicitly. Saved to project credentials. | + +## Multiple agents and multiple containers + +- **Different devices, same container tag**: fully supported. Many agents can mount the same container concurrently from different machines. +- **Same device, same container tag, mounted twice**: not supported. Use one mount per container per device. +- **Same device, different containers**: mount as many as you want in parallel. + +## Commands + +Every `smfs` subcommand. Click any one to expand. + + + + Mount a container. Defaults to `.//`; pass `--path` to mount elsewhere. + + ```bash + smfs mount agent_memory + smfs mount agent_memory --path ~/memory + ``` + + See the flags table above for everything you can pass. + + + + Unmount a running mount. Drains pending writes up to `--drain-timeout`, then exits the daemon. Anything not drained resumes on the next mount. + + ```bash + smfs unmount agent_memory + ``` + + Inside the mount, you can omit the tag and let SMFS resolve it from the nearest `.smfs` marker. + + ```bash + smfs unmount + smfs unmount --force + ``` + + + + List every SMFS mount running on this machine. + + ```bash + smfs list + ``` + + + + Show daemon status for a mount: connectivity, queue depth, last sync. Auto-detects the tag via the nearest `.smfs` marker. + + ```bash + smfs status + smfs status agent_memory + smfs status --json + ``` + + + + Tail the daemon log for a mount. Auto-detects the tag via the nearest `.smfs` marker. + + ```bash + smfs logs + smfs logs -f + smfs logs -n 500 + ``` + + + + Force an immediate sync cycle. Push pending writes, pull remote changes. + + ```bash + smfs sync agent_memory + ``` + + Inside the mount, the tag is optional (resolved from the nearest `.smfs` marker). + + ```bash + smfs sync + ``` + + + + Semantic search across a container without being inside the mount. The optional second argument scopes the search to a subpath inside the container. Inside a mount, plain `grep` already does this; `smfs grep` is the explicit form for scripts. + + ```bash + smfs grep "deadline" + smfs grep "deadline" /notes/ + ``` + + + + One-time auth. Prompts for your Supermemory API key and stores it in your global credentials. You can also pass it directly with `--key`. + + ```bash + smfs login + smfs login --key sm_... + ``` + + + + Print the currently-authenticated user, organization, and API endpoint. + + ```bash + smfs whoami + ``` + + + + Remove stored credentials. Active mounts keep running until you `smfs unmount` them. + + ```bash + smfs logout + ``` + + + + Force-installs the shell wrapper that makes plain `grep` semantic inside mounts. Writes directly to `~/.zshrc`. `smfs mount` also installs it automatically the first time, so you only need this to refresh after an upgrade. + + ```bash + smfs init + ``` + + Reopen your terminal (or `source ~/.zshrc`) after running it. + + + + Self-install. Copies the running binary to `~/.local/bin` and resets permissions. Run this if your `smfs` install ever feels broken. + + ```bash + smfs install + ``` + + + +## FAQ + + + + Run `smfs init` to force-install the shell wrapper. It writes directly to `~/.zshrc`. Then reopen your terminal so the new shell picks it up. + + The wrapper only triggers when you're inside a mount (it looks for the `.smfs` marker file at the mount root). Outside a mount, `grep` stays normal. Inside a mount, any flag you pass falls through to the real `grep`. + + + + Not yet. SMFS supports macOS (arm64, x64) and Linux (arm64, x64) for now. Windows isn't on the v0 roadmap. + + On Windows, use the [Bash Tool](/smfs/bash-tool) instead. It runs anywhere TypeScript runs and gives your agent the same `ls`, `cat`, `grep`, `sgrep` surface without needing a mount. + + + + Re-mount with `--clean` to wipe the local cache and pull everything fresh from the API: + + ```bash + smfs unmount agent_memory + smfs mount agent_memory --clean + ``` + + Nothing on the server changes; only the local SQLite cache gets reset. + + + + Yes. Once a container is mounted, anything on that machine can read and write through the mount path. The constraint is one mount per container tag per device. Mount it once, point both agents at the same folder. + + + + Yes, absolutely. Mount the same container tag from each sandbox. Bidirectional sync keeps everything in step as either side writes, so Agent A in sandbox 1 sees Agent B's writes from sandbox 2 within a sync interval. + + To avoid stepping on each other, give each agent its own subdirectory (`/agent_a/`, `/agent_b/`, etc.). They can still read across the whole mount, cross-reference each other's findings, and build on each other's work. The shared container is the point. + + diff --git a/apps/docs/smfs/overview.mdx b/apps/docs/smfs/overview.mdx new file mode 100644 index 00000000..da26a6c6 --- /dev/null +++ b/apps/docs/smfs/overview.mdx @@ -0,0 +1,49 @@ +--- +title: "SMFS" +sidebarTitle: "Overview" +description: "Memory your agent can grep." +icon: "database" +--- + +**SMFS** mounts your Supermemory container as a real directory. Agents read it with `ls`, `cat`, and `grep`. No SDK to learn, no client to wire up, no embeddings to think about. + +SMFS is open source and free for everyone. + +## Why a filesystem + +Every model already knows how a filesystem works. It can `ls`, `cat`, `grep`, `find`, redirect with `>`, pipe with `|`. You don't have to teach it a new API surface, and the grammar carries across runtimes. + +The catch: a filesystem on its own isn't great for memory. Search means walking the tree. Long files burn through context. The model has to hold the directory structure in its head. None of that scales as memory grows. + +SMFS fixes the catch. The shell is real, but underneath: + +- **Semantic `grep` by default.** One call surfaces what matters across the whole container, ranked by meaning. Pass any flag and you fall through to the real `grep` for exact matches. +- **Memory paths get distilled.** Files marked as memory paths are extracted and indexed by Supermemory. They don't bloat the model's context. +- **Virtual `profile.md`.** A live digest of the container at the mount root. The model can `cat profile.md` for a one-shot summary instead of walking every file. +- **Bidirectional sync** runs in the background. Local reads hit cache; writes push to Supermemory. + +You get filesystem ergonomics without paying the filesystem tax in tokens. + +## Two ways to use SMFS + +Pick by where your agent runs. + + + + For agents and tools with a real filesystem. Claude Code, Cursor, devcontainers, Docker, Codespaces. NFSv3 on macOS, FUSE on Linux. + + + For agents running serverless or at the edge. Cloudflare Workers, AWS Lambda, Vercel. A virtual bash where the filesystem is your container. + + + +## Next steps + + + + One curl, one mount, you're done. + + + Drop SMFS into a TypeScript agent without mounting anything. + +