Skip to main content
Glama
aiagate

memtree

by aiagate
README.md
# memtree

Codex and Claude Code session JSONL is collected outside the model context,
consolidated into local SQLite memory, and exposed through MCP.

This is an intentionally small first implementation:

- Codex and Claude Code Hook queueing
- crash-recovery transcript scanning
- byte-offset incremental JSONL collection
- secret redaction and user/final-assistant filtering
- deterministic per-session Sleep memory
- SQLite FTS search
- MCP read, search, explicit write, forget, Sleep, and status tools
- stdio and Streamable HTTP transports

The current Sleep implementation creates a bounded session digest. It does not
yet perform LLM-based profile/entity/decision extraction.

## Setup

```bash
cd ~/repos/memtree
uv sync
uv run memtree init
uv tool install --editable .
```

The editable tool install makes `memtree` available to lifecycle hooks.

## Configure hooks

Merge the relevant example into the user-level configuration:

- Codex: `integrations/codex/hooks.json.example` into `~/.codex/hooks.json`
- Claude Code: `integrations/claude-code/settings.json.example` into
  `~/.claude/settings.json`

Review and trust the Codex hook through `/hooks`. Hooks only enqueue
`session_id`, `transcript_path`, and `cwd`; they do not invoke MCP or a model.

## Collect and Sleep

Run manually or from cron/systemd:

```bash
memtree collect --scan all
memtree sleep
memtree status
memtree memory list --cwd "$PWD"
```

Suggested daily command:

```bash
memtree collect --scan all && memtree sleep
```

## Configure MCP

Codex stdio configuration:

```toml
[mcp_servers.memtree]
command = "memtree"
args = ["serve", "--transport", "stdio"]
enabled = true
```

Claude Code:

```bash
claude mcp add --scope user memtree -- \
  memtree serve --transport stdio
```

Available tools:

- `memory_context`
- `memory_search`
- `memory_get`
- `memory_put`
- `memory_forget`
- `memory_sleep`
- `memory_status`

Write and forget tools are annotated with their side effects. Automatic
transcript ingestion is deliberately not exposed as an MCP tool.

Pass `cwd` to `memory_context` or `memory_search` to include the matching
project memory. Use `include_all_projects=true` only for an intentional
cross-project review.

## Docker

Docker runs the Streamable HTTP MCP server with a private persistent volume:

```bash
docker compose up --build -d
```

The HTTP endpoint is `http://127.0.0.1:8765/mcp`. Collection normally runs on
the host because the transcript directories are private host state.

## Development

```bash
uv run ruff format --check .
uv run ruff check .
uv run pyright
uv run pytest
```