agent-clifs
A virtual filesystem for AI agents. Unix commands they already know. Zero dependencies.
Load documents, codebases, or any text into an in-memory filesystem and let your AI agent explore it with ls, grep, find, tree, and more.
Install
pip install agent-clifs
Quick Start
from agent_clifs import AgentCLI
cli = AgentCLI()
# Load your content
cli.execute("mkdir -p /docs/api")
cli.execute("write /docs/api/users.md '# Users API\nGET /users\nPOST /users'")
cli.execute("write /docs/api/auth.md '# Auth API\nPOST /auth/login'")
# An agent explores just like a developer would
cli.execute("tree /docs") # See the structure
cli.execute("grep -rn 'POST' /docs") # Search for patterns
cli.execute("cat /docs/api/users.md") # Read a file
Bulk Loading
The most common pattern — load from a dictionary:
from agent_clifs import AgentCLI, VirtualFileSystem
vfs = VirtualFileSystem()
vfs.load_from_dict({
"/src/app.py": "from flask import Flask\napp = Flask(__name__)",
"/src/models.py": "class User:\n ...",
"/docs/setup.md": "# Setup\nRun `pip install -r requirements.txt`",
})
cli = AgentCLI(vfs)
cli.execute("find /src -name '*.py'")
Use with Any Agent Framework
Just pass cli.execute as a tool function:
from langchain.tools import Tool
tool = Tool(
name="filesystem",
description="Execute filesystem commands: ls, cat, grep, find, tree, head, tail, wc",
func=cli.execute,
)
AgentCLI Configuration
AgentCLI(
vfs=None,
structured=False,
readonly=False,
allowed_commands=None,
disabled_commands=None,
bm25_top_files=None,
)
| Parameter | Type | Default | Description |
|---|---|---|---|
vfs |
VirtualFileSystem | None |
None |
Existing VFS to use; creates a new empty one if omitted |
structured |
bool | set[str] |
False |
LLM-optimized output (see below) |
readonly |
bool |
False |
Disable all write commands (write, append, rm, cp, mv, mkdir, touch) |
allowed_commands |
set[str] | None |
None |
Whitelist of permitted commands; mutually exclusive with disabled_commands |
disabled_commands |
set[str] | None |
None |
Blacklist of forbidden commands; mutually exclusive with allowed_commands |
bm25_top_files |
int | None |
None |
Enable BM25 pre-filtering for grep (see below) |
structured mode
Controls token-efficient output formatting for LLM consumption:
False— raw Unix-style output (default)True— apply LLM formatting to all supported commands:ls,tree,grep,find,wcset[str]— apply formatting only to the specified commands, e.g.structured={"grep", "tree"}
cli = AgentCLI(structured=True)
# grep (standard) # grep (structured)
/docs/api/auth.md:3:POST /api/auth [/docs/api/auth.md]
/docs/api/users.md:3:POST /api/users L3: POST /api/auth
[/docs/api/users.md]
L3: POST /api/users
BM25 pre-filtering
When working with large codebases, grep -r can search hundreds of files and flood the LLM with results. Setting bm25_top_files builds an in-memory BM25 index over all loaded files and silently restricts each grep call to the top-N most relevant files — the LLM calls grep exactly as it normally would.
vfs = VirtualFileSystem()
vfs.load_from_dict(your_codebase) # thousands of files
cli = AgentCLI(vfs, bm25_top_files=10)
# The LLM sees normal grep output, but only the 10 most
# relevant files were searched — fewer tokens, less noise.
cli.execute("grep -rn 'def authenticate' /")
The index is built once at initialisation. If you load more files afterwards, call cli.reindex() to rebuild it:
cli = AgentCLI(bm25_top_files=10)
cli.vfs.load_from_dict(more_files)
cli.reindex()
How it works: query terms are extracted from the grep pattern (regex metacharacters are stripped so only literal words remain), files are scored with BM25, and only the top-N are passed to the regex engine. If no literal terms can be extracted from the pattern (e.g. grep -r '.*' /), BM25 filtering is skipped and all files are searched normally.
Command access control
# Only allow read commands
cli = AgentCLI(allowed_commands={"ls", "cat", "grep", "find", "tree", "head", "tail", "wc", "pwd"})
# Or just disable specific ones
cli = AgentCLI(disabled_commands={"rm", "mv"})
# Shorthand for disabling all writes
cli = AgentCLI(readonly=True)
Commands
Pipes (|) and output redirection (>, >>) are supported between commands.
| Command | Description | Key Flags |
|---|---|---|
ls |
List directory | -l -h -R -S -a -d -1 -r -F |
tree |
Directory tree | -L -d -a |
cat |
Display files | -n -b -s |
head / tail |
First/last lines | -n -c |
grep |
Search contents | -r -i -n -l -c -v -w -x -F -o -A/-B/-C --include --exclude --max-depth |
find |
Find files/dirs | -name -iname -type -path -size -empty -maxdepth -mindepth -delete |
sed |
Stream editor | -n -e; supports p, d, q, = commands |
wc |
Count lines/words/bytes | -l -w -c -m |
mkdir |
Create directory | -p -v |
touch |
Create empty file | -c |
write |
Write content to file | write <path> <content> |
append |
Append content to file | append <path> <content> |
cp |
Copy | -r -a -n -v |
mv |
Move/rename | -f -n -v |
rm |
Remove | -r -f -v |
pwd / cd |
Navigate | cd - cd ~ |
Use cli.help() for full help text, or cli.help("grep") for a specific command.
Python API
Direct access to the underlying VFS:
from agent_clifs import VirtualFileSystem
vfs = VirtualFileSystem()
vfs.load_from_dict({"/file.txt": "hello"}) # bulk load
content = vfs.read_file("/file.txt") # read
vfs.write_file("/new.txt", "world") # write
vfs.mkdir("/data", parents=True) # create directory
snapshot = vfs.to_dict() # export as {path: content}
License
Unlicense — public domain.
Release files for agent-clifs 1.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| agent_clifs-1.3.0.tar.gz | 47.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agent_clifs-1.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 82.2 kB
Release files / agent_clifs-1.3.0.tar.gz
| Download URL | agent_clifs-1.3.0.tar.gz |
|---|---|
| Size | 47.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3cdc6b9bd4a9b816fd302c35d10caf012778712e7d6989a02777b4947003e6de
|
|
BLAKE2b-256 checksum How to use checksums |
326bb2125d151fd915eaac64b865470c94baa40f6daca266a82dfb795ea8d1ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / agent_clifs-1.3.0-py3-none-any.whl
| Download URL | agent_clifs-1.3.0-py3-none-any.whl |
|---|---|
| Size | 35.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
39264613697f4253a9e2242058e67fa5c5df431669df1395dbb1889731ae1207
|
|
BLAKE2b-256 checksum How to use checksums |
71feafcbf768afba1bd9a2090d448acd3ceafbfc65186fe34ac0facc725a8db2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|