Skip to content

timothyandrew/memtree

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

memtree

Filesystem-based memory tree for AI agents. Persist conversation context on disk in a tree structure grouped by topic — agents keep top-level summaries in context and load deeper levels on demand.

Why

AI agents lose context as conversations grow and get compressed. memtree gives them a structured place to save and retrieve knowledge across sessions. The CLI is designed to be called directly by agents (via tool use / shell commands), and the included Claude Code skills provide ready-made /memtree-save and /memtree-load slash commands.

This project is built almost entirely with Claude Code (this includes the READMEs and all other text in this repo) and is an exploration of how tree-based memory might improve on Claude's existing flat-file auto-memory. It's a working experiment, not a polished tool.

How It Looks

graph TD
    root[".memtree/"]
    root --- rust["rust/"]
    root --- python["python/"]
    root --- tools["tools/"]

    rust --- errors["errors.md<br/><i>Error handling patterns</i>"]
    rust --- async["async/"]
    rust --- lifetimes["lifetimes.md<br/><i>Ownership & borrowing rules</i>"]

    async --- tokio["tokio.md<br/><i>Tokio runtime usage</i>"]
    async --- streams["streams.md<br/><i>Async iterator patterns</i>"]

    python --- decorators["decorators.md<br/><i>Decorator patterns</i>"]
    python --- typing["typing.md<br/><i>Type hint cheatsheet</i>"]

    tools --- git["git/"]
    tools --- docker["docker.md<br/><i>Dockerfile best practices</i>"]

    git --- rebase["rebase.md<br/><i>Interactive rebase workflow</i>"]
    git --- hooks["hooks.md<br/><i>Useful git hooks</i>"]

    style root fill:#f9f,stroke:#333
    style rust fill:#ffd,stroke:#333
    style python fill:#ffd,stroke:#333
    style tools fill:#ffd,stroke:#333
    style async fill:#ffd,stroke:#333
    style git fill:#ffd,stroke:#333
    style errors fill:#fff,stroke:#333
    style lifetimes fill:#fff,stroke:#333
    style tokio fill:#fff,stroke:#333
    style streams fill:#fff,stroke:#333
    style decorators fill:#fff,stroke:#333
    style typing fill:#fff,stroke:#333
    style docker fill:#fff,stroke:#333
    style rebase fill:#fff,stroke:#333
    style hooks fill:#fff,stroke:#333
Loading

Directories (yellow) hold topic summaries. Leaves (white) hold the actual memories with frontmatter.

Install

cargo install --path .

Quick Start

# Store a memory
memtree store --path rust/errors --summary "Error handling patterns" \
  --content "Use thiserror for library errors, anyhow for applications." \
  --tags rust,errors

# Store a directory summary
memtree store --path rust --summary "Rust programming topics"

# List the tree
memtree ls --depth 2
# rust/                    Rust programming topics
#   errors.md              Error handling patterns

# Print the entire tree
memtree inspect

# Recall a memory
memtree recall rust/errors

# Search across all memories
memtree search thiserror

# Move
memtree move rust/errors rust/error-handling

# Delete
memtree delete rust/error-handling

Claude Code Skills

memtree ships with two Claude Code skills that give agents slash commands for saving and loading context. Copy the skills/ directory into your project or symlink it.

/memtree-save — Save conversation context

Invoked manually when you want Claude to persist everything from the current conversation. The agent audits the full conversation, extracts every piece of information (decisions, code changes, errors, architecture, etc.), and stores them as leaves in the tree. It also writes a ## Memtree index to CLAUDE.md with @import syntax so future sessions auto-discover the tree.

> /memtree-save

# Claude will:
# 1. Run memtree inspect to check existing tree
# 2. Extract every topic from the conversation
# 3. Store each as a leaf with full verbatim content
# 4. Add directory summaries
# 5. Update CLAUDE.md with @import tree index
# 6. Print the final tree

/memtree-load — Load relevant context

Invoked with a prompt describing what you're working on. The agent searches the tree, recalls matching leaves, and presents a structured summary.

> /memtree-load working on the OAuth integration

# Claude will:
# 1. Run memtree ls --depth 2 for tree overview
# 2. Search for keywords: "OAuth", "integration", "auth"
# 3. Recall full content of matching leaves
# 4. Present a structured summary grouped by topic

Tree Root

Resolved in order:

  1. --root <path> flag
  2. MEMTREE_ROOT environment variable
  3. .memtree/ in the current working directory (default)

The root is auto-created on first write.

On-Disk Format

<root>/
├── _summary.md              # root summary (plain text)
├── rust/
│   ├── _summary.md          # "Rust programming topics"
│   ├── errors.md            # leaf with YAML frontmatter + body
│   └── async/
│       ├── _summary.md
│       └── tokio.md
└── python/
    ├── _summary.md
    └── decorators.md

Leaf files have YAML frontmatter:

---
summary: "Rust error handling patterns"
created: 2026-03-09T12:00:00Z
updated: 2026-03-09T12:00:00Z
tags: [rust, errors]
---

Use `thiserror` for library errors
and `anyhow` for application errors.

Directory summaries (_summary.md) are plain text.

Commands

Command Description Locks
store --path <path> --summary <text> [--content <text>] [--tags t1,t2] Create/update a leaf (with content) or directory summary (without) Yes
recall <path> [--full] Print leaf body or directory summary + children No
ls [path] [--depth N] Tree listing with summaries No
inspect Print entire tree with all summaries (no leaf content) No
search <query> Case-insensitive substring search across all leaves No
move <src> <dst> Move a leaf or subtree Yes
delete <path> [--force] Remove a leaf or subtree Yes

Concurrency

Write commands acquire an exclusive flock on <root>/.memtree.lock. Read commands don't lock. Writes are atomic (temp file + rename), so readers never see partial content.

Auto-Promotion

Storing a nested path under an existing leaf automatically promotes it to a directory. For example, storing at rust/errors/handling when rust/errors.md exists moves it to rust/errors/errors.md and creates the rust/errors/ directory.

Piping Content

Use --content - to read content from stdin:

echo "Memory content" | memtree store --path notes/idea --summary "An idea" --content -

About

Tree-based memory layout for agents

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages