Mount PostgreSQL as a filesystem. Build apps with files, explore databases with ls and cat. Every write is logged and undoable.
Mount PostgreSQL as a filesystem. Build apps with files, explore databases with ls and cat. Every write is logged and undoable.
A versioned filesystem backed by PostgreSQL, and a filesystem interface to PostgreSQL. Built for agents.
Every file is a real PostgreSQL row. Directories are tables. File contents are columns. Multiple agents and humans can read and write the same files concurrently with full ACID guarantees. Every change is versioned and fully reversible. No sync protocols. No coordination layer. The filesystem is the API.
You can use TigerFS in two ways:
File-first: Write markdown with frontmatter or other file types, organize into directories. Writes are atomic, changes are versioned, and everything is reversible: optionally take a savepoint, try changes, roll back individual or all changes if they don't work out. Any tool that works with files -- Claude Code, Cursor, grep, vim -- just works. Build lightweight workspaces via the filesystem: multi-agent task coordination is just mv'ing files between todo/doing/done directories.
Data-first: Mount any Postgres database and explore it with ls, cat, grep, and other unix tools. For
large databases, chain filters into paths that push down to SQL (e.g., the last 10 orders by customer 123 can be found at directory path
.by/customer_id/123/.order/created_at/.last/10/.export/json). No database client or SQL needed.
Both modes are backed by the same transactional database. You get real transactions, true concurrent access, and a SQL escape hatch when you need it. TigerFS mounts via FUSE on Linux and NFS on macOS, no extra dependencies needed.
TigerFS ships with agent skills for Claude Code, Gemini CLI, Codex, and others, automatically installed at mount time. The skills teach your agent to read, write, search, and -- new in 0.7 -- safely roll back any change. You don't need to learn the filesystem interface. Just ask:
The skills teach both modes -- file-first (file and markdown workspaces, directory-as-state recipes like kanban, history with savepoints and atomic undo) and data-first (index lookups, pipeline filters with SQL pushdown, PATCH updates, DDL via .create//.delete/) -- all through the shared dot-directory control surface that turns every capability into a filesystem path. For details on what's underneath, read on.
curl -fsSL https://install.tigerfs.io | shNew project? Start file-first. Existing database? Start data-first.
Your data lives in regular files and directories. Metadata, queries, and operations live in dot-directories: invisible by default, always available.
$ ls /mnt/db/notes/
hello.md tutorials/
$ ls -a /mnt/db/notes/
. .. .history/ .log/ .savepoint/ .undo/ hello.md tutorials/Dot-directories are the control surface. Navigate them to browse history, filter data, undo changes, and manage schemas, all through the same filesystem interface.
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Unix Tools │────▶│ Filesystem │────▶│ TigerFS │────▶│ PostgreSQL │
│ ls, cat, │ │ Backend │ │ Daemon │ │ Database │
│ echo, rm │◀────│ (FUSE/NFS) │◀────│ │◀────│ │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘| File-first | Data-first |
|---|---|
.history/ past versions |
.info/ table metadata |
.log/ operation log with diffs |
.by/ index lookups |
.savepoint/ bookmarks for undo |
.filter/ column filtering |
.undo/ preview and apply undo |
.order/, .first/, .last/ sort and paginate |
.build/ create workspaces |
.export/, .import/ bulk I/O |
.create/, .modify/, .delete/ schema management |
Workspaces tell TigerFS how to present a table as a native file format. Write "markdown" to .build/ and the table becomes a directory of .md files with YAML frontmatter:
# Mount a database and create a workspace with history
tigerfs mount postgres://localhost/mydb /mnt/db
echo "markdown,history" > /mnt/db/.build/blog
# Write a post. Frontmatter becomes columns, body becomes text
cat > /mnt/db/blog/hello-world.md /mnt/db/.build/notesEvery write -- create, edit, rename, delete -- is captured in the operation log with timestamp and user identity. From there, four capabilities follow:
Browse past versions. .history// lists every snapshot of a file; read one to see what it looked like at that point. Useful for "what did this look like last week?" without invoking undo.
ls /mnt/db/notes/.history/plan.md/ # all snapshots
cat /mnt/db/notes/.history/plan.md/2026-04-12T14:23:00Z # one specific versionBrowse what happened. The operation log records who changed what, when. Filter by recency, user, or operation type, and diff any individual edit:
cat /mnt/db/notes/.log/.last/10/.export/json # 10 most recent operations
cat /mnt/db/notes/.log/.by/user_id/agent-7/.last/5/.export/json # filtered by user
diff -u /mnt/db/notes/.log//before /mnt/db/notes/.log//current # diff a specific editSavepoints for sandboxed exploration. Create a named bookmark, try changes, preview what an undo would touch, roll back if it doesn't pan out:
echo '{"description":"Before refactoring"}' > /mnt/db/notes/.savepoint/before-refactor.json
# ... edit multiple files ...
diff -ru /mnt/db/notes/.undo/to-savepoint/before-refactor /mnt/db/notes/ -x '.*' # review
touch /mnt/db/notes/.undo/to-savepoint/before-refactor/.apply # applyAuto-savepoints (--auto-savepoint-interval, default 30m) record bookmarks at session-boundary inactivity gaps, so there's always a recent checkpoint available.
Granular undo. Reverse one operation by log id, everything since a log id, or everything since a savepoint:
touch /mnt/db/notes/.undo/id//.apply # one operation
touch /mnt/db/notes/.undo/to-id//.apply # everything since that log entry
touch /mnt/db/notes/.undo/to-savepoint/before-refactor/.apply # everything since savepoint
touch /mnt/db/notes/.undo/to-savepoint/before-refactor/.by/user_id/agent-7/.apply # only agent-7's changes since savepointPer-user filtering makes agents reversible independently in collaborative workspaces. Undo operations are themselves logged and reversible: changing your mind about an undo is just one more .apply.
See docs/history.md for the full guide.
You don't have to run any of the commands above yourself. Once TigerFS is mounted, just talk to your agent:
You: "Undo the recent changes to why-postgres.md"
Agent: Reads the recent log... Each edit via Claude's Write/Edit becomes 3 log entries (create temp, delete target, rename), so the two edits I see produce 6 entries. I'll apply them newest-first to roll back to the saved state.
019e73d9-33c0-...(rename)019e73d9-33bf-...(delete)019e73d9-33b5-...(create temp)019e73d9-2b1f-...(rename)019e73d9-2b1e-...(delete)019e73d9-2b11-...(create temp)Apply all 6?
Because the operation log is structured and queryable through the filesystem, the agent reasons about composite operations on its own. The skills teach the patterns; you stay in natural language.
Shared agent workspace.
Multiple agents and humans operate on the same knowledge base concurrently. Changes are visible instantly. Every edit is automatically versioned, so if one agent overwrites another's work, browse the full edit trail in .history/ and recover it.
# Agent A writes research findings
cat > /mnt/db/kb/auth-analysis.md /mnt/db/.build/tasks
mkdir /mnt/db/tasks/todo /mnt/db/tasks/doing /mnt/db/tasks/done
# Agent claims a task by moving it to doing
mv /mnt/db/tasks/todo/fix-auth-bug.md /mnt/db/tasks/doing/fix-auth-bug.md
# Marks it complete
mv /mnt/db/tasks/doing/fix-auth-bug.md /mnt/db/tasks/done/fix-auth-bug.md
# See what everyone is working on
ls /mnt/db/tasks/doing/
grep "author:" /mnt/db/tasks/doing/*.mdSafe exploration. An agent creates a savepoint, investigates a bug, makes changes across multiple files. If the approach doesn't work, undo atomically to the savepoint. Every file reverts in one step.
# Agent creates savepoint before investigating
echo '{"description":"Before investigating auth bug"}' > /mnt/db/notes/.savepoint/pre-investigation.json
# Agent explores, edits multiple files...
# User reviews: "that's not right, roll it back"
touch /mnt/db/notes/.undo/to-savepoint/pre-investigation/.apply
# All files restored to pre-investigation stateMount any Postgres database and explore it with ls, cat, grep. Every path resolves to optimized SQL pushed down to the database.
Filesystem Database
────────── ────────
/mnt/db/ → tables (default schema)
/mnt/db/users/ → rows (by PK)
/mnt/db/users/123/ → columns as files
/mnt/db/.schemas/ → all schemas (including default)$ ls -a /mnt/db/users/
. .. .by/ .filter/ .order/ .first/ .last/ .info/ .export/ .import/
1/ 2/ 3/ 4/ 5/ ...Explore an unfamiliar database. Point an agent at a mounted database and it understands the schema immediately using ls and cat. No SQL, no database client, no connection strings to pass around.
Quick data fixes. Update a customer's email, toggle a feature flag, delete a test record. One shell command instead of opening a SQL client, remembering the table schema, and writing a WHERE clause.
Export and analyze. Chain filters, ordering, and pagination into a single path, then pipe the result into jq, awk, or export as CSV for a spreadsheet.
# Mount an existing database
tigerfs mount postgres://localhost/mydb /mnt/db
ls /mnt/db/ # List tables
ls /mnt/db/users/ # List rows (by primary key)
cat /mnt/db/users/123.json # Row as JSON
cat /mnt/db/users/123/email.txt # Single column
cat /mnt/db/users/.by/email/[email protected] # Index lookupecho '[email protected]' > /mnt/db/users/123/email.txt # Update column
echo '{"email":"[email protected]","name":"A"}' > /mnt/db/users/123.json # Update via JSON (PATCH)
mkdir /mnt/db/users/456 # Create row
rm -r /mnt/db/users/456/ # Delete rowSame model on the data side. You ask, the agent navigates the schema and pipeline paths. Two examples.
Exploration -- agent reads the schema as files:
You: "I'm new to this database. What's in the orders table?"
Agent: Reads
/mnt/db/orders/.info/columns,/mnt/db/orders/.info/count, and a sample of 5 rows...Shape: 47,283 rows, 8 columns. Indexed on
customer_id,status,created_at.Columns:
id(uuid PK),customer_id(uuid),status(pending/shipped/delivered/cancelled),total(numeric),created_at/shipped_at(timestamptz, shipped_at nullable),payment_method,currency.Recent activity: mostly status=shipped, paymen
No open issues yet, or sync has not completed.