Skip to content
/ loopy Public

An in-memory, zero-side-effect filesystem API over a single Python string

Notifications You must be signed in to change notification settings

tg1482/loopy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Loopy: an in-memory, zero-side-effect filesystem API over a single Python string.

Loopy is a filesystem sandbox whose entire state lives in a single string. It comes with a bash‑style shell so you or your agent can navigate, search, and manipulate a tree‑structured knowledge base with composable commands.

The idea is to simulate a file system to build and navigate a knowledge tree with POSIX-style commands that agents are already familiar with.

from loopy import Loopy
from loopy.shell import run

raw = "<root><concepts><ml><supervised><classification>predicts categories</classification></supervised></ml></concepts></root>"
tree = Loopy(raw)
# tree.raw == "<root><concepts><ml><supervised><classification>predicts categories</classification></supervised></ml></concepts></root>"
# tree.tree("/") ==
# root/
# └── concepts/
#     └── ml/
#         └── supervised/
#             └── classification: predicts categories

output = run("cd /concepts/ml/supervised && cat classification", tree)
# output == "predicts categories"

run('touch /concepts/ml/supervised/regression "predicts continuous values"', tree)

serialized = tree.raw
# serialized == "<root><concepts><ml><supervised><classification>predicts categories</classification><regression>predicts continuous values</regression></supervised></ml></concepts></root>"
# tree.tree("/") ==
# root/
# └── concepts/
#     └── ml/
#         └── supervised/
#             ├── classification: predicts categories
#             └── regression: predicts continuous values

Why?

When an agent processes information, it needs somewhere to put it - somewhere it can search, reorganize, and grow organically. For any type of knowledge base like agent memories, product taxonomies, etc the challenge is to expose CRUD type interactions without a pile of specialized tools (search, create, delete, etc.) that are added to context.

Recursive Language Models (RLMs) introduced the idea of putting the entire context into a Python variable and let the model recursively interact with it, instead of reasoning over everything in one shot. RLMs: https://alexzhang13.github.io/blog/2025/rlm/. I really liked it, but enabling a python REPL seemed like a bad tradeoff for generality.

Loopy imposes a known structure (a tree / filesystem), and replaces the python REPL with a bash syntax over a string. Agents are RL'd in filesystem-like setups, and this provides a sandboxed way to give an agent access to a knowledge base without touching the OS filesystem.

Why this approach:

  • simple - a single string can represent the full data
  • known structure - stored in a file system format agents already know and love
  • composition - compose search commands to quickly navigate the data

How it works

Loopy keeps an in-memory node tree and exposes filesystem-like operations. There is no OS filesystem I/O; all mutations stay in memory until you serialize. The raw string is generated on demand and can be parsed back into the same structure.

<root><concepts><ml><supervised>...</supervised></ml></concepts></root>
from loopy import Loopy

tree = (
    Loopy()
    .mkdir("/concepts/ml/supervised", parents=True)
    .touch("/concepts/ml/supervised/regression", "predicts continuous values")
    .touch("/concepts/ml/supervised/classification", "predicts categories")
    .mkdir("/concepts/ml/unsupervised")
    .touch("/concepts/ml/unsupervised/clustering", "groups similar items")
)

tree.grep("predicts", content=True)  # find concepts by description
tree.find("/concepts", type="f")  # all leaf concepts
tree.ls("/concepts/ml")  # ['supervised', 'unsupervised']

# tree.raw
# <root><concepts><ml><supervised><regression>predicts continuous values</regression><classification>predicts categories</classification></supervised><unsupervised><clustering>groups similar items</clustering></unsupervised></ml></concepts></root>

File-backed

from loopy import FileBackedLoopy, load, save

tree = FileBackedLoopy("notes.loopy")
tree.touch("/ideas/mcp", "Expose shell with MCP")  # auto-saved

tree = load("notes.loopy")
tree.mkdir("/scratch", parents=True)
save(tree, "notes.loopy")  # explicit save for non-file-backed trees

Install

# Local install
uv pip install -e .

# PyPI
uv pip install loopy-fs

API

Core Operations

Method Description
mkdir(path, parents=True) Create directory (category)
touch(path, content) Create file (entity) with content
cat(path) Read content
ls(path) List children
rm(path, recursive=True) Delete node
mv(src, dst) Move/rename
cp(src, dst) Copy
ln(target, link) Create symlink
exists(path) Check existence

Search

Method Description
grep(pattern, content=True) Search by regex
find(path, type="f") Find by type (f=file, d=dir, l=link)
glob(pattern) Glob patterns (**/*.py)

Navigation

Method Description
cd(path) Change directory
.cwd Current directory
.. support tree.ls("..") works

Inspection

Method Description
tree(path) Pretty print hierarchy
du(path) Count nodes
info(path) Metadata dict
isdir(path) / isfile(path) Type checks
islink(path) Check if symlink
readlink(path) Get symlink target
backlinks(path) Find all symlinks pointing to path
walk(path) os.walk() style
.raw The underlying string

All mutating operations return self for chaining.

Not all commands are supported in the shell format yet. Working towards it.

Shell

Loopy includes a bash-style command runner designed for agents. Use run() to navigate and compose operations directly against the in-memory tree.

from loopy import Loopy
from loopy.shell import run

tree = (
    Loopy()
    .mkdir("/concepts/ml/supervised", parents=True)
    .touch("/concepts/ml/supervised/classification", "predicts categories")
)

output = run(
    "cd /concepts/ml && ls | grep supervised && cat supervised/classification",
    tree,
)

Start a REPL loop from a file-backed database (auto-saves on every mutation):

uv run python -m loopy.shell notes.loopy

Start a REPL loop with a sample database:

uv run python -m loopy.shell examples/product_catalog.loopy

Quick shell example:

loopy> ls -R sports
sports:
fitness/
outdoor/

loopy> find /sports -type f
/sports/fitness/weights/dumbbells_set
/sports/fitness/cardio/yoga_mat
/sports/outdoor/camping/tent_4person
/sports/outdoor/hiking/backpack_40L

Shell Commands

Command Description
ls [path] [-R] List directory contents
cd <path> Change directory
pwd Print working directory
cat [path] [--range start len] Show file contents
head [path] [-n N] Show first N lines (default 10)
tail [path] [-n N] Show last N lines (default 10)
wc [-lwc] [path] Count lines/words/chars
sort [-rnu] [path] Sort lines
tree [path] Show tree structure
find [path] [-name pat] [-type d|f|l] Find files/directories/symlinks
grep <pat> [path] [-i] [-v] [-c] Search by regex
du [path] [-c] Count nodes or content size
info [path] Show node metadata
touch <path> [content] Create file
write <path> [content] Write to file (overwrites)
mkdir [-p] <path> Create directory
rm [-r] <path> Remove file/directory
mv <src> <dst> Move/rename
cp <src> <dst> Copy
ln <target> <link> Create symlink
readlink <path> Show symlink target
sed <path> <pat> <repl> [-i] [-r] Search and replace
split <delim> [path] Split content by delimiter
echo <text> Print text
printf <fmt> [args] Print formatted text
help Show help

Command Chaining

Operator Description
cmd1 | cmd2 Pipe output of cmd1 to cmd2
cmd1 ; cmd2 Run both, continue on failure
cmd1 && cmd2 Run cmd2 only if cmd1 succeeds
cmd1 || cmd2 Run cmd2 only if cmd1 fails

Example Databases

Loopy ships with example databases in examples/:

  • product_catalog.loopy - E-commerce taxonomy
  • knowledge_graph.loopy - ML/CS concept ontology
  • bookmarks.loopy - Browser bookmarks
  • recipes.loopy - Recipe collection
  • org_chart.loopy - Company org chart
uv run python -m loopy.shell examples/knowledge_graph.loopy
loopy> cat /concepts/ml/deep_learning/architectures/transformer
def:Attention-based architecture|prereq:attention,mlp|paper:attention_is_all_you_need

loopy> grep "prereq:.*transformer" -c
2

Or load in Python:

from loopy.file_store import load

tree = load("examples/product_catalog.loopy")
tree.ls("/clothing/mens/shoes")  # ['loafers_brown']
tree.grep("price:.*99", content=True)  # products ending in .99

License

MIT

About

An in-memory, zero-side-effect filesystem API over a single Python string

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •