Skip to main content

Self-maintaining code memory for AI coding agents: an Obsidian-compatible knowledge graph of your codebase, served over MCP and auto-curated from your work sessions.

Project description

Tremula

PyPI Python License: MIT

Populus tremuloides — the quaking aspen. The Pando colony is thousands of trunks sharing one living root system. Tremula gives your codebases the same shape of memory: one knowledge graph per project, connected at the roots where projects actually meet.

Tremula is self-maintaining memory for AI-assisted development. It keeps an Obsidian-compatible markdown knowledge graph about your codebase — modules, key functions, architectural decisions, conventions, cross-service contracts — and maintains it automatically while you work.

Why

AI coding agents start every session amnesiac, and hand-written docs rot. Tremula closes both gaps with two cooperating loops:

  • Reactive — an MCP server exposing six tools to any MCP client: search, get_context (a topic plus its graph neighbors), read_note, write_note, link_notes, split_note.
  • Ambient — lifecycle hooks that work without being asked: capture session events to a cheap local log, inject the vault's index at session start, silently attach the few notes relevant to the files being touched, and distill durable knowledge (decisions, conventions, contracts) into notes in a debounced background process.

Retrieval is a funnel, never a dump: a ~2k-token index at session start, graph-expanded context on demand, small working-context attachments per prompt. Context overhead stays constant no matter how large the vault grows.

How the vault gets built and maintained

Mechanism When Cost
tremula bootstrap --brief once, instant zero LLM — docstrings + tree-sitter AST
tremula bootstrap [target ...] wherever you choose to go deep ~one small LLM call per module
background distiller as you work (debounced, ≥10 min apart) one small LLM call per run
revision janitor every 5th distill run or tremula revise splits oversized notes, merges duplicates, archives stale ones

Module dependency links come from the tree-sitter import graph — computed, never hallucinated. The distiller is agent-agnostic: by default it auto-detects whichever agent CLI you already have on PATH (claude, gemini, codex, …) and shells out to it — no API key, no vendor lock-in. Point it at a specific CLI, an explicit command, or the Anthropic API in one config line (see Choosing the model provider).

Safety model

  • Markdown is the source of truth. SQLite/FTS5 is a rebuildable cache. Edit notes in Obsidian or any editor; changes are picked up automatically.
  • Hand-written notes are protected. Machine writes are marked source: distilled. The distiller updates its own notes freely but may only enrich yours — through an LLM judge plus a deterministic no-content-loss backstop.
  • Projects are isolated by construction. A session resolves its own vault plus explicitly declared shared vaults (roots) — any other address is unresolvable, not merely filtered.
  • Nothing is deleted. Cleanup archives to attic/ inside the vault, with git history as the deeper tombstone.
  • Hooks are fail-silent and never slow a session. Kill switch: TREMULA_HOOKS_DISABLED=1.

Federation

Connect repositories where they actually meet:

tremula root add webapp-api --members webapp,api

Shared contracts live in the bridge vault as one note per endpoint with a section per side (## Provider (api) / ## Consumer (webapp)). Each project's tooling can only edit its own section — so when the sides disagree, the drift is visible in one file instead of hidden between two repos.

Install & set up

Manually

uv tool install tremula-mcp      # or: pip install tremula-mcp
                                 # zero-install alternative: uvx tremula-mcp <cmd>

cd ~/code/your-project
tremula registry init            # creates tremula-vault/ + registers the project
                                 # name it: registry init --name webapp_frontend

# Big or JS/TS repo? List build-output dirs in .tremulaignore (see below) BEFORE
# bootstrapping — otherwise they crowd real source out under the module cap.
tremula bootstrap --brief        # instant zero-LLM vault (whole project)
# or scope it to where the code lives:   tremula bootstrap src/ app/
# later, deep-enrich where it matters:   tremula bootstrap src/core/

The project key defaults to the directory name. To pin a stable key (e.g. webapp_frontend rather than frontend), pass --name, or set TREMULA_PROJECT — including in .mcp.json's env block, so the server and the registration agree. Re-running registry init --name <new> --force from a registered repo renames it.

bootstrap prunes node_modules, .venv, build output, and Tremula's own state by default. For project-specific build dirs, drop a .tremulaignore at the repo root — one directory name per line, committed with the project:

.next
.sst
.open-next

(A machine-wide default is also available via bootstrap_skip_dirs in ~/.tremula/config.yaml.)

Wire it into Claude Code, inside the project:

{ "mcpServers": { "tremula": { "command": "tremula", "args": ["serve"] } } }

— save that as .mcp.json (the six memory tools). For the ambient loop (capture → inject → attach → distill), copy examples/claude-settings.json into .claude/settings.json — every hook entry just runs tremula hook <Event>. Restart the session and approve the server + hooks when asked.

Or ask your agent

Paste this into Claude Code (or any agent with shell access) inside your project:

Set up Tremula code-memory here. Install it with uv tool install tremula-mcp. Before running anything that writes, ask me three things and wait for my answers:

  1. Project key — default is this directory's name (<dir>). Suggest a stable, unambiguous key if the dir name is generic (e.g. webapp_frontend rather than frontend).
  2. Scope — bootstrap the whole repo, or focus on specific source dirs (e.g. src/, app/)? Recommend focusing for a large repo.
  3. Ignores — gather build-output dir candidates two ways: read any existing ignore files (.gitignore, .dockerignore, .npmignore, .eslintignore, …) for already-declared dirs, and scan the tree for common ones (.next, .sst, .open-next, dist, build, coverage). Drop those already covered by the defaults, show me the rest, and confirm before writing a repo-root .tremulaignore (one dir name per line). This keeps generated files out of the vault.

Then, using my answers: run tremula registry init (add --name <key> if I chose a custom one), then tremula bootstrap --brief (append the focus dirs if I scoped it). Create .mcp.json registering an MCP server named tremula with stdio command tremula serve (add an env.TREMULA_PROJECT set to my key if it differs from the dir name). In .claude/settings.json, add hooks running tremula hook <Event> for SessionStart, UserPromptSubmit, PostToolUse, Stop, PreCompact, and SessionEnd. Finally, show me the resulting vault note count and ask me to restart the session.

Open tremula-vault/ in Obsidian for the graph view. Machine-written notes queue in the auto-section of _index.md; moving a link up into your curated headings endorses it.

Working from a source checkout instead? git clone … && uv sync, then use uv run tremula … and point .mcp.json/hook commands at .venv/bin/tremula (this repo's own .mcp.json shows the pattern).

Choosing the model provider

Bootstrap (full mode) and the background distiller need an LLM. Tremula is agent-agnostic and ships with no vendor default — set provider in ~/.tremula/config.yaml:

# Default: auto-detect an agent CLI on PATH (claude / gemini / codex / …) and
# shell out to it. No API key. If several are installed, pin one with `agent`.
provider:
  kind: auto
  # agent: claude        # optional: pin when multiple CLIs are present

# Pin a specific agent CLI by name:
# provider: { kind: cli, agent: gemini }

# Or run any one-shot CLI completer. "{prompt}" => prompt as an arg; omit it and
# the prompt is piped on stdin. "{model}" => the `model` field below.
# provider:
#   kind: cli
#   command: ["llm", "-m", "gpt-4o-mini", "{prompt}"]

# Or the Anthropic API (the only path that needs a key):
# provider:
#   kind: anthropic
#   model: claude-haiku-4-5-20251001
#   auth_env: ANTHROPIC_API_KEY        # read from this env var
#   # base_url: http://localhost:8080  # Anthropic-compatible local endpoint

auto needs no key — it uses whatever your installed CLI is already authenticated with. Only kind: anthropic reads auth_env. bootstrap --brief makes zero LLM calls, so it needs no provider at all.

Client support

The server speaks standard MCP over stdio — Claude Code, Cursor, Codex, Gemini CLI, or anything else that talks MCP. The ambient loop ships wired for Claude Code's hook lifecycle; any host that can run a command on lifecycle events can drive the same tremula hook <event> CLI.

Status

Core complete and self-hosting: this repository's own vault is maintained by Tremula, and roughly three quarters of its notes were written by the system while the system was being written. 220+ tests, ruff-clean.

Roadmap: hybrid semantic search (sqlite-vec) · long-lived HTTP daemon · native file watcher.

Develop

uv sync --extra dev
uv run pytest                  # TREMULA_LIVE_TESTS=1 uv run pytest -m live for real-LLM tests
uv run ruff check src tests

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

tremula_mcp-0.1.5.tar.gz (84.8 kB view details)

Uploaded Source

Built Distribution

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

tremula_mcp-0.1.5-py3-none-any.whl (67.3 kB view details)

Uploaded Python 3

File details

Details for the file tremula_mcp-0.1.5.tar.gz.

File metadata

  • Download URL: tremula_mcp-0.1.5.tar.gz
  • Upload date:
  • Size: 84.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for tremula_mcp-0.1.5.tar.gz
Algorithm Hash digest
SHA256 13a1ce0ddaae62a1fc2d71269290edfd1ca0f8f294cb53cc6b8398fea23a4d6d
MD5 5bf063c93fc8242c06176de7309ac893
BLAKE2b-256 33eebbab4bb07860e012c3020c6f0993ac578a7f58265b8c9d11e42c51d1e878

See more details on using hashes here.

File details

Details for the file tremula_mcp-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: tremula_mcp-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 67.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for tremula_mcp-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 8fd7a601c7fa8d0b246416c5d898a3c9342db5c45097c3fda46941f83c1e0954
MD5 116c2c7eb17a54cf1bcb4880ce90bb6f
BLAKE2b-256 d247479f65edb9424a9c18cbc44003f675647d5ec4d19eb1fcf04b7c14f7f177

See more details on using hashes here.

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