dendrite-rlm
v0.1.0
Published
Recursive Language Model (RLM) framework for OpenCode — long-term memory and task decomposition powered by Trilium Notes
Maintainers
Readme
Dendrite
Recursive Language Model (RLM) framework for OpenCode, powered by Trilium Next.
Dendrite gives your AI coding agent persistent long-term memory and the ability to recursively decompose complex tasks across multiple sub-agents — each with a clean context window. No more context overflow. No more re-explaining your codebase.
┌─────────────────────────────────────────────────────┐
│ Orchestrator │
│ "Add auth to API and update frontend" │
│ │
│ 1. rlm_recall("auth API") ← remembers prior │
│ 2. rlm_decompose([...]) ← splits into 4 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │worker │ │worker │ │worker │ parallel │
│ │JWT mid. │ │user model│ │frontend │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ └─────────────┼───────────┘ │
│ ▼ │
│ 3. rlm_collect([...]) ← gathers results │
│ 4. rlm_persist("decision...") ← remembers for │
│ next session │
└─────────────────────────────────────────────────────┘
│ fetch()
▼
┌───────────┐
│ Trilium │ shared state + long-term memory
│ Next │ (self-hosted, your data stays yours)
└───────────┘Why Dendrite?
| Problem | How Dendrite solves it | |---|---| | Context window overflow on large tasks | Decomposes work across sub-agents, each with a fresh context | | Agent forgets prior sessions | Persists decisions, context, and patterns to Trilium | | Agent re-explores code it already analyzed | Recalls prior knowledge before starting work | | Coordination overhead eats tokens | Batched custom tools — 5 tool calls instead of ~16 | | Session compaction loses important context | Plugin auto-injects Trilium knowledge index on compaction | | Manual memory management | Plugin auto-stores session breadcrumbs on idle |
Requirements
- OpenCode (installed and configured)
- Trilium Next instance (local or remote)
- Node.js >= 18
- An ETAPI token from Trilium (Options > ETAPI > Create Token)
Quick Start
1. Install
# From your project root
npx dendrite-rlm initThis copies tools, plugins, prompts, commands, and agent configs into your project.
If you already have an opencode.json, it will be merged (not overwritten).
To overwrite existing files:
npx dendrite-rlm init --force2. Set environment variables
export TRILIUM_ETAPI_TOKEN="your-token-here" # Options > ETAPI > Create Token
export TRILIUM_API_URL="http://localhost:8080/etapi" # Default; change if remoteAdd these to your shell profile (~/.zshrc, ~/.bashrc) for persistence.
3. Restart OpenCode
opencodeOpenCode will automatically pick up the new tools, plugins, agents, and commands.
4. Initialize Trilium
Run the setup command inside OpenCode to create the note hierarchy:
/setup-rlmThis creates the following structure in Trilium (idempotent — safe to run multiple times):
RLM/ #rlm
├── tasks/ #rlm-type=tasks (coordination)
├── knowledge/ #rlm-type=knowledge (persistent memory)
│ ├── decisions/ #rlm-kb=decisions
│ ├── context/ #rlm-kb=context
│ ├── errors/ #rlm-kb=errors
│ └── patterns/ #rlm-kb=patterns
└── sessions/ #rlm-type=sessions (session history)5. Verify
/recall testIf Trilium is reachable, you'll see "No relevant prior context found" (expected on first run).
You can also check your setup from the terminal:
npx dendrite-rlm doctorUsage
Automatic (recommended)
Just use OpenCode normally. The orchestrator will automatically:
- Recall prior context before non-trivial tasks
- Decompose complex tasks (> 3 files) into sub-agent work
- Persist important decisions and context after completing work
The AGENTS.md rules guide when decomposition happens vs. direct work.
Slash Commands
| Command | Description |
|---|---|
| /setup-rlm | Create Trilium note hierarchy (one-time) |
| /decompose <task> | Explicitly decompose a task using RLM |
| /recall <query> | Search Trilium memory for prior context |
| /status | Show active/pending/done RLM tasks |
Examples
# Let the orchestrator decide how to handle it
Add JWT authentication to the API layer and update the frontend auth context
# Explicitly decompose
/decompose Refactor the database layer to use connection pooling across all services
# Search prior context
/recall authentication decisions
# Check task progress
/statusArchitecture
Components
.opencode/
├── lib/
│ └── rlm-config.ts Shared Trilium ETAPI client
├── tools/
│ ├── rlm.ts Orchestrator tools (5 tools)
│ ├── rlm-worker.ts Worker tools (2 tools)
│ └── rlm-setup.ts One-time Trilium setup
├── plugins/
│ ├── rlm-persistence.ts Auto-persist on session idle
│ └── rlm-compaction.ts Inject memory on context compaction
├── prompts/
│ ├── orchestrator.md Orchestrator system prompt
│ ├── worker-code.md Code worker prompt
│ ├── worker-analyze.md Analysis worker prompt
│ └── worker-debug.md Debug worker prompt
└── commands/
├── setup-rlm.md /setup-rlm
├── decompose.md /decompose
├── recall.md /recall
└── status.md /statusTools
Orchestrator tools (available to the build agent):
| Tool | What it does | Replaces |
|---|---|---|
| rlm_recall | Searches knowledge + sessions in parallel | 3-4 MCP calls |
| rlm_decompose | Batch-creates task notes with attributes | 6-8 MCP calls |
| rlm_collect | Batch-reads results from multiple tasks | 3-4 MCP calls |
| rlm_persist | Stores knowledge entry with dedup check | 3-4 MCP calls |
| rlm_status | Lists pending/in-progress/done tasks | 2-3 MCP calls |
Worker tools (available to sub-agents):
| Tool | What it does |
|---|---|
| rlm-worker_start | Reads task spec, marks in-progress |
| rlm-worker_complete | Writes result, marks done/error |
Agents
| Agent | Type | Purpose |
|---|---|---|
| build | Primary | Orchestrator — decomposes, delegates, composes |
| plan | Primary | Read-only planning (can recall/persist, cannot decompose) |
| worker-code | Subagent (hidden) | Focused code implementation |
| worker-analyze | Subagent (hidden) | Read-only code analysis/review |
| worker-debug | Subagent (hidden) | Focused debugging |
All agents use the globally configured model — no model overrides.
Plugins (zero LLM cost)
| Plugin | Trigger | Action |
|---|---|---|
| rlm-persistence | session.idle | Auto-stores session breadcrumb to Trilium |
| rlm-compaction | session.compacting | Injects knowledge index into compacted context |
RLM Workflow
1. RECALL → Search Trilium for prior context
2. ASSESS → Does this need decomposition?
3. DECOMPOSE → Split into 2-5 focused subtasks
4. DELEGATE → Send to workers (parallel when possible)
5. COMPOSE → Gather results, synthesize answer
6. PERSIST → Store new knowledge for future sessionsDecomposition Strategies
| Task Type | Strategy | |---|---| | Feature implementation | Split by layer: data model → API → UI → tests | | Codebase refactoring | Split by module or file group | | Complex debugging | Sequential: reproduce → isolate → fix → verify | | Code review | Parallel by concern: security, performance, correctness |
Performance
Compared to raw MCP tool calls (e.g., using trilium-mcp-server directly):
| Metric | Raw MCP | Dendrite | Improvement | |---|---|---|---| | Orchestrator tool calls per task | ~16 | ~5 | 62% fewer | | Total tool calls (3 subtasks) | ~28-34 | ~12 | 58-65% fewer | | Context tokens for coordination | ~5,000-8,000 | ~1,500-2,500 | 65-70% fewer | | Session persistence | Manual | Automatic | Zero cost | | Post-compaction memory | Lost | Preserved | Automatic |
Configuration
Environment Variables
| Variable | Default | Description |
|---|---|---|
| TRILIUM_API_URL | http://localhost:8080/etapi | Trilium ETAPI endpoint |
| TRILIUM_ETAPI_TOKEN | (required) | ETAPI token from Trilium |
Customizing
Change default Trilium URL: Set TRILIUM_API_URL environment variable.
Add model overrides: Add "model": "provider/model-id" to any agent in opencode.json.
Adjust decomposition threshold: Edit the "When to decompose" section in AGENTS.md.
Add knowledge categories: Create new child notes under knowledge/ in Trilium with #rlm-kb=<category> label, then update the rlm_persist tool's enum in rlm.ts.
Disable auto-persistence: Delete .opencode/plugins/rlm-persistence.ts.
Disable compaction injection: Delete .opencode/plugins/rlm-compaction.ts.
Troubleshooting
| Symptom | Fix |
|---|---|
| "RLM tasks parent note not found" | Run /setup-rlm |
| "ETAPI 401" | Regenerate token: Trilium > Options > ETAPI > Create Token |
| "ETAPI 404" | Verify URL includes /etapi path |
| Tools not appearing in OpenCode | Restart OpenCode after adding files |
| Plugin not storing sessions | Check logs for rlm-persistence warnings |
| Workers not being invoked | Verify worker-* agents are in opencode.json with hidden: true |
How It Works (Under the Hood)
Dendrite does not use an MCP server. All Trilium access happens through OpenCode's
Custom Tools which call Trilium's ETAPI
directly via fetch(). This eliminates the MCP server subprocess and keeps ~15 MCP
tool descriptions out of the agent's context window.
The Plugins hook into OpenCode's event system to automatically persist sessions and inject context during compaction — with zero LLM involvement.
Worker sub-agents are invoked via OpenCode's built-in Task tool, giving each worker a completely fresh context window containing only its task spec.
Project Structure
dendrite/
├── .opencode/ # OpenCode extension files
│ ├── package.json # Plugin dependencies
│ ├── tools/ # Custom tools (Trilium ETAPI)
│ ├── plugins/ # Event-driven automation
│ ├── prompts/ # Agent system prompts
│ └── commands/ # Slash commands
├── plan/ # Design documents & specs
├── opencode.json # OpenCode configuration
├── AGENTS.md # Agent behavioral rules
└── README.md # This fileLicense
MIT
Credits
- OpenCode — the AI coding agent this extends
- Trilium Next — the self-hosted note app used as shared state
- Model Context Protocol — the protocol that inspired the tool design
