Persistent virtual filesystem for AI agents, backed by SQLite or Postgres
Project description
agent-vfs
The best AI agents already use filesystems as memory. Now your agent can too.
agent-vfs gives your agent a persistent virtual filesystem backed by your own database. Agents use familiar file operations (read, write, ls, grep) while data lives in SQLite or Postgres.
pip install agent-vfs
from agent_vfs import FileSystem, open_database
db = open_database("memory.db") # SQLite, auto-creates table
fs = FileSystem(db, "agent-1")
fs.write("/notes.md", "# Meeting Notes\n- Ship agent-vfs")
content = fs.read("/notes.md")
Persistent memory that survives restarts, multi-tenant by default, no external services. One table in your database. Zero dependencies for SQLite (uses Python's built-in sqlite3).
Also available for TypeScript: npm install agent-vfs (docs)
Use with any AI SDK
OpenAI SDK
from openai import OpenAI
from agent_vfs import FileSystem, open_database, openai
db = open_database("memory.db")
fs = FileSystem(db, user_id)
tools, handle_tool_call = openai(fs)
response = OpenAI().chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
)
for call in response.choices[0].message.tool_calls or []:
result = handle_tool_call(call.function.name, call.function.arguments)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": result["text"],
})
Anthropic SDK
from anthropic import Anthropic
from agent_vfs import FileSystem, open_database, anthropic
db = open_database("memory.db")
fs = FileSystem(db, user_id)
tools, handle_tool_call = anthropic(fs)
response = Anthropic().messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=messages,
tools=tools,
)
for block in response.content:
if block.type == "tool_use":
result = handle_tool_call(block.name, block.input)
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": block.id,
"content": result["text"],
}],
})
Example: chat agent with persistent memory
The most common pattern is an agent that loads its memory at the start of each session, then reads and writes files as it chats.
from anthropic import Anthropic
from agent_vfs import FileSystem, open_database, anthropic
db = open_database("memory.db")
fs = FileSystem(db, user_id)
tools, handle_tool_call = anthropic(fs)
# Boot: load the agent's memory into the system prompt
try:
memory = fs.read("/memory.md")
except FileNotFoundError:
memory = "(no memory yet)"
system = f"""You are a helpful assistant with persistent memory.
Your current memory:
{memory}
You have filesystem tools. Use them to remember things across sessions.
Save important facts to /memory.md. Organize notes in folders as needed."""
messages = []
while True:
user_input = input("> ")
messages.append({"role": "user", "content": user_input})
response = Anthropic().messages.create(
model="claude-sonnet-4-20250514",
max_tokens=4096,
system=system,
messages=messages,
tools=tools,
)
while response.stop_reason == "tool_use":
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = handle_tool_call(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result["text"],
})
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
response = Anthropic().messages.create(
model="claude-sonnet-4-20250514",
max_tokens=4096,
system=system,
messages=messages,
tools=tools,
)
text = "".join(b.text for b in response.content if b.type == "text")
print(text)
messages.append({"role": "assistant", "content": response.content})
Tools (16)
| Tool | Description | Key Options |
|---|---|---|
read |
Read a file | offset, limit (line range) |
write |
Write a file (auto-creates parent dirs) | summary (optional description for search/ls) |
edit |
Find-and-replace (unique match required) | |
multi_edit |
Multiple find-and-replace edits in one call | |
append |
Append to a file (creates if missing) | |
ls |
List directory | recursive, summaries |
mkdir |
Create directory (idempotent, creates parents) | |
rm |
Remove file or directory (recursive) | |
grep |
Search file contents (regex) | case_insensitive |
glob |
Find files by name (glob pattern) | type (file/dir) |
mv |
Move or rename (overwrites target) | |
search |
Semantic search across all files (FTS5 + optional vectors) | path, limit |
tag |
Add a tag to a file or directory | |
untag |
Remove a tag from a file or directory | |
find_by_tag |
Find all files with a specific tag | path (scope) |
recent |
List recently modified files | limit, path (scope) |
Search
Built-in full-text search (FTS5) with optional vector embeddings for hybrid semantic search.
from agent_vfs import FileSystem, open_database
from agent_vfs.search import open_search
db = open_database("memory.db")
# FTS5 only (zero dependencies):
search = open_search(db, user_id)
# Hybrid FTS5 + vector (just add an API key):
search = open_search(db, user_id, "openai", os.environ["OPENAI_API_KEY"])
fs = FileSystem(db, user_id, search_index=search)
fs.write("/notes.md", "Architecture decisions", summary="Key design choices")
results = fs.search("architecture")
Supported embedding providers: openai, openai-large, voyage, voyage-large, mistral. Or pass a custom url, model, api_key, and dimensions to open_embeddings().
Multi-tenancy
One database, many users. Each FileSystem is scoped by user ID with full isolation at the DB layer:
db = open_database("memory.db")
alice_fs = FileSystem(db, "alice")
bob_fs = FileSystem(db, "bob")
alice_fs.write("/secret.txt", "alice only")
bob_fs.read("/secret.txt") # raises NotFoundError
Production database
pip install agent-vfs[postgres]
from agent_vfs import open_database, FileSystem
db = open_database("postgresql://user:pass@localhost/mydb")
fs = FileSystem(db, user_id)
Or bring your own connection:
from agent_vfs.db.postgres import PostgresDatabase
import psycopg2
conn = psycopg2.connect("postgresql://...")
db = PostgresDatabase(conn)
db.initialize()
fs = FileSystem(db, user_id)
Custom table name:
db = open_database("app.db", table_name="agent_files")
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_vfs-0.2.0.tar.gz.
File metadata
- Download URL: agent_vfs-0.2.0.tar.gz
- Upload date:
- Size: 23.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a1ba9951b5572296fb7da3d8f9273e3c2d7b9c6850b05672867d750e4f1039e8
|
|
| MD5 |
c8724a6341922557efd923d231c3fd67
|
|
| BLAKE2b-256 |
00114f445bd9be828ff5ec61d398b6e5556377fb8f2c9bb9e485e9c154061297
|
Provenance
The following attestation bundles were made for agent_vfs-0.2.0.tar.gz:
Publisher:
publish.yml on johannesmichalke/agent-vfs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_vfs-0.2.0.tar.gz -
Subject digest:
a1ba9951b5572296fb7da3d8f9273e3c2d7b9c6850b05672867d750e4f1039e8 - Sigstore transparency entry: 1077220813
- Sigstore integration time:
-
Permalink:
johannesmichalke/agent-vfs@f4db620182e9dddf79aec3f06001fd8f9e226c8d -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/johannesmichalke
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f4db620182e9dddf79aec3f06001fd8f9e226c8d -
Trigger Event:
release
-
Statement type:
File details
Details for the file agent_vfs-0.2.0-py3-none-any.whl.
File metadata
- Download URL: agent_vfs-0.2.0-py3-none-any.whl
- Upload date:
- Size: 24.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a9ddb6ee0f3271c7c1b741771bd4e1f81d78b0d0f71206d082d7ddcccaecd4f
|
|
| MD5 |
ede43fbb09a0acbba6621f7af921e7fa
|
|
| BLAKE2b-256 |
b086186b65f64379a03c81449281e6e9bd43f82f5a2d512ce87e4e87671d3279
|
Provenance
The following attestation bundles were made for agent_vfs-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on johannesmichalke/agent-vfs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_vfs-0.2.0-py3-none-any.whl -
Subject digest:
9a9ddb6ee0f3271c7c1b741771bd4e1f81d78b0d0f71206d082d7ddcccaecd4f - Sigstore transparency entry: 1077220826
- Sigstore integration time:
-
Permalink:
johannesmichalke/agent-vfs@f4db620182e9dddf79aec3f06001fd8f9e226c8d -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/johannesmichalke
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f4db620182e9dddf79aec3f06001fd8f9e226c8d -
Trigger Event:
release
-
Statement type: