Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_vfs-0.2.0.tar.gz (23.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_vfs-0.2.0-py3-none-any.whl (24.1 kB view details)

Uploaded Python 3

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

Hashes for agent_vfs-0.2.0.tar.gz
Algorithm Hash digest
SHA256 a1ba9951b5572296fb7da3d8f9273e3c2d7b9c6850b05672867d750e4f1039e8
MD5 c8724a6341922557efd923d231c3fd67
BLAKE2b-256 00114f445bd9be828ff5ec61d398b6e5556377fb8f2c9bb9e485e9c154061297

See more details on using hashes here.

Provenance

The following attestation bundles were made for agent_vfs-0.2.0.tar.gz:

Publisher: publish.yml on johannesmichalke/agent-vfs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for agent_vfs-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9a9ddb6ee0f3271c7c1b741771bd4e1f81d78b0d0f71206d082d7ddcccaecd4f
MD5 ede43fbb09a0acbba6621f7af921e7fa
BLAKE2b-256 b086186b65f64379a03c81449281e6e9bd43f82f5a2d512ce87e4e87671d3279

See more details on using hashes here.

Provenance

The following attestation bundles were made for agent_vfs-0.2.0-py3-none-any.whl:

Publisher: publish.yml on johannesmichalke/agent-vfs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page