Self-hosted service
supermemoryai/smfs avatar
supermemoryai/smfs

Inside an smfs mount, flagless grep stops meaning grep

A filesystem designed for agents, with SOTA retrieval, automatic memory profiles, sync engine. Drop any file type (pdf, images, videos), and grep through them.

493 stars36 forksRustMIT

At a glance

What is it?
A Rust filesystem that mounts a Supermemory container as a real directory and hijacks grep to make it semantic, where macOS mounts over a pure-Rust NFSv3 server instead of FUSE, the memory-paths flag writes scope back to the container tag, unmount drains a push queue for 30 seconds, and the documented container image is referenced before it is published.
Who is it for?
Read this as infrastructure for an agent that already has a shell, not as a memory product, because the value is that a directory of files becomes greppable without a new tool. Three consequences decide whether it fits your setup.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • supermemoryai/smfs493 ★ · +15
Star history
Repository2026-09-112026-11-14
supermemoryai/smfs478493

15 Stars in the last 64 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Inside a mount, flagless grep stops meaning grep

The pitch is that there is no new command to learn. `smfs init` installs a grep wrapper, and after that, inside a mount, a flagless `grep` becomes a semantic query while any flag drops through to the real binary:

sh
cd agent_memory/

grep "OAuth refresh tokens"          # semantic: finds files about the topic
grep "design review notes" work/     # semantic, scoped to a directory

grep -F "exact string" notes.md      # any flag falls through to real grep
grep -rF "literal" .                 # also real grep (literal substring)

So `grep pattern` finds files about a topic, and `grep -F pattern file` finds a literal string. The boundary between the two is the presence of any flag, and it is detected by a hidden `.smfs` marker in the directory, with `grep` left completely unchanged outside a mount. That design is what lets an agent keep using the command it already knows, and it is also the sharpest edge in the project: the meaning of a standard tool depends on the current directory, so a script written to grep for a fixed string will silently return topic matches unless somebody remembers to add `-F`. The escape hatch is `smfs grep "query" --tag <container_tag>`, which does the same semantic search from outside a mount.

macOS mounts over an NFSv3 server the binary runs itself

The mount flag makes the platform difference explicit: `--backend fuse|nfs`, defaulting to fuse on Linux and nfs on macOS. The manifest explains why in a comment. `fuser` is Linux-only, and on macOS it would require macFUSE, which the project says it explicitly avoids. `nfsserve` is unix-wide and pure Rust, used as the NFSv3 server on macOS and optionally as an alternate backend on Linux. So on a Mac, mounting a container means running an NFS server, in-process, serving a directory back to the same machine, and that path has different privilege requirements and different failure modes from the FUSE path. Linux has the choice of either backend, and the two are not interchangeable in behaviour, so a workflow that works on one Mac is not automatically a workflow that works on a Linux laptop.

The memory-paths flag writes its scope back to the container tag

Not every file in a mount is memory. Only files under the container's memory paths go through the Supermemory pipeline that extracts structured facts and makes them semantically searchable, and everything else is plain durable storage. The default scope is whatever the server has configured for that container, and `--memory-paths` overrides it per mount with a comma separated list, where a trailing slash matches any file inside that folder recursively and no trailing slash is an exact file match. An empty value disables memory generation entirely and leaves the mount as pure storage, and omitting the flag leaves the server configuration alone. The part worth pausing on is what the override does: the flag writes the configuration to the container tag, so the next mount anywhere sees the same scope until it is changed again. A command that looks like opening a directory is also editing remote state.

Unmount drains a push queue with a 30 second budget

Writes are asynchronous. Edits inside the mount upload to Supermemory in the background, and remote changes pull in on an interval that defaults to 30 seconds, configurable with `--sync-interval <secs>` and disableable with `--no-sync`, which keeps the push side running. At unmount the daemon drains the push queue, with `--drain-timeout <secs>` defaulting to 30. The command list describes `smfs unmount` as unmounting and draining pending pushes, and `smfs status <tag>` as reporting daemon health and queue depth, so the depth is observable. The arithmetic is straightforward and worth doing out loud: a large write started seconds before unmount can still be queued when the 30 second budget expires, and the local cache is then either discarded or left behind. Two flags govern that cache, `--ephemeral` for an in-memory cache where nothing persists after unmount and `--clean` to wipe the local cache before mounting.

Install is a curl piped into bash from the project's own domain

The install line is `curl -fsSL https://smfs.ai/install | bash`, and the script is fetched from the product domain rather than from a release asset, a package registry or a tagged URL. That is a common shape for a small binary and it means the thing you execute is whatever that endpoint serves at the moment you run it. The supported targets are macOS on arm64 and x64 and Linux on arm64 and x64, with no Windows path in the installer at all, which lines up with the NFS-versus-FUSE split rather than being an omission. A Supermemory API key is required, stored once by `smfs login`, and `smfs whoami` will show the current user, organisation and API endpoint. Building from source instead is `cargo build --release` against Rust 1.80 or newer, with a `rust-toolchain.toml` and a committed `Cargo.lock` at the root.

The documented container image is written in the future tense

The release image is built from this checkout with a separate Dockerfile under `docker/`, and then the next section says that when an official image is published the same run flags apply, giving a command against `ghcr.io/supermemoryai/smfs:latest`. So the documented `docker run` invocation points at a tag that the text itself describes as not yet published. The flags it passes are the interesting part regardless of when the image lands, because mounting inside a container needs the FUSE device and a raised capability:

sh
docker run --rm -it \
  --device /dev/fuse \
  --cap-add SYS_ADMIN \
  -e SUPERMEMORY_API_KEY="$SUPERMEMORY_API_KEY" \
  smfs:dev mount agent_memory --path /mnt/memory

`--device /dev/fuse` with `--cap-add SYS_ADMIN` is a privileged mount, and it is the Linux path. A Mac user following the same shape in a Linux container gets the FUSE backend by default, not the NFS one their host would have used.

The image installs OpenSSL build dependencies for a client that uses rustls

The Dockerfile has a builder stage on `rust:1.80-slim` that installs `pkg-config` and `libssl-dev` through apt before running `cargo build --release --bin smfs`, and the workspace manifest configures the HTTP client as `reqwest` with `default-features = false` and the features `json`, `rustls-tls` and `multipart`. Rustls does not link against the system OpenSSL, so the two build dependencies the builder image installs are not needed to build this binary. They are harmless and they slow the build, but the more useful reading is that the manifest deliberately removed the native TLS default, which is what makes the `rust:1.80-slim` builder possible without a heavier base. The runtime stage is `debian:bookworm-slim` with `ca-certificates` and `fuse3` and nothing else, copying one binary in and setting `smfs` as the entrypoint with `--help` as the default command.

The manifest annotates dependencies with milestone numbers nobody explains

The workspace dependencies carry comments that are not about dependencies. The HTTP client is marked as milestone six, the SQLite cache as milestone five, and the mount backends as milestone three, in a scheme that appears nowhere in the documentation. The two milestones in between are therefore invisible from outside, which makes the list read as a roadmap fragment rather than as a rationale. The workspace itself is only two crates, `smfs-core` and `smfs`, which is small for a sync engine with two mount backends, a SQLite cache and a semantic search path. The tree also holds both `bash/` and `bash-py/`, while the documentation covers only the TypeScript package, so the Python port of the virtual bash tool exists in the repository without a page. Two other lines stop mid-word: the command table ends at `smfs init` described as installing the gr, and the devcontainer note ends at the phrase the devcontainer buil.

Editorial conclusion

Read this as infrastructure for an agent that already has a shell, not as a memory product, because the value is that a directory of files becomes greppable without a new tool. Three consequences decide whether it fits your setup. Inside a mount, `grep` with no flags is a semantic search, so any script or agent that relied on literal substring matching needs `-F` added, and the boundary is a hidden `.smfs` marker rather than anything visible in the prompt. On macOS the mount is served by an NFSv3 server the binary runs itself, since the manifest says macFUSE is explicitly avoided, which is a different set of privileges and failure modes from the FUSE path used on Linux. And a mount is not read-only: `smfs mount` with `--memory-paths` writes the scope back to the container tag, and unmount drains a push queue with a 30 second default timeout, so a large write immediately before unmount may still be in flight. The last commit on the default branch main is dated 18 August 2026 and the newest release is v0.0.5 from 7 May 2026.

Frequently asked questions

How does smfs make grep semantic?

smfs init installs a grep wrapper. Inside a mount, detected by a hidden .smfs marker, a flagless grep routes to Supermemory's semantic index, and any flag falls through to the real grep, so grep -F searches for a literal string. Outside a mount grep is unchanged, and smfs grep with a --tag runs a semantic search from outside one.

Which files in an smfs mount become searchable memories?

Only files under the container's memory paths, which is the part Supermemory's pipeline processes to extract structured facts. The --memory-paths flag overrides the scope per mount, with a trailing slash matching recursively and no trailing slash matching one exact file, and an empty value disables memory generation entirely.

How does smfs mount work on macOS?

Not through FUSE. The --backend flag defaults to fuse on Linux and nfs on macOS, because fuser is Linux-only and would need macFUSE on macOS, which the project avoids. On macOS the binary runs a pure-Rust NFSv3 server, nfsserve, and serves the mount to the same machine.

What does smfs unmount do with pending writes?

It drains the push queue, with --drain-timeout defaulting to 30 seconds. Writes upload in the background and remote changes pull every 30 seconds by default, adjustable with --sync-interval or disableable with --no-sync, which keeps local writes pushing. smfs status reports daemon health and queue depth.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. supermemoryai/smfs on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/supermemoryai-smfs.svg)](https://hysenlabs.com/projects/supermemoryai-smfs)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/supermemoryai-smfs.svg)](https://hysenlabs.com/projects/supermemoryai-smfs)

Was this useful?