What MonkeyLLM is
Knowledge lives in a forest: a directory of markdown nodes under git, each one carrying a curated passport of title, summary, tags and typed edges, plus the lightweight indexes that make it findable. An agent does not receive a retrieval dump. It drops in through search, follows edges, reads exactly the node it needs, and plants what it learned as a new node.
Concretely, that gives you three things a vector store does not:
- A file tree you can read. Every node is a markdown file with frontmatter.
git logworks. Code review works. A human correction and an agent write land in the same history. - Tabular payloads that stay tabular. A CSV or a spreadsheet becomes a real SQLite table with a generated query manual, queried with read-only SQL, not chunked into prose.
- A memory that outlives the conversation. What one agent writes today, another reads next month, over the same MCP contract.
The spec is the truth
The engine follows a normative specification, not the other way round. The highest numbered docs/monkeyllm-spec-v*.md in the repository is authoritative, and everything documented in this section is derived from the code that implements it.
Navigation, not retrieval
Classic RAG answers a question by embedding it, pulling the top k chunks, and hoping the answer is inside them. That works until an answer needs two facts that never appear in the same chunk.
A forest answers it by moving. The agent locates entry points, reads a cheap digest of a node before paying for its body, follows a typed edge to a neighbour, and only picks the full text when the summary says this is the one. Every call is token budgeted and every truncation is explicit, so the agent always knows what it did not read.
Two more mechanics matter. Successful hunts deposit pheromone on the trail they used and mint shortcut links, so a corpus that is used becomes cheaper to navigate. And a harvest() call collapses the whole loop into one round trip when you would rather reason over ranked evidence yourself.
How the pieces fit
The engine is a plain Python package with no server, no host and no UI attached. Everything else in the repository sits around it, and none of it is required: a forest on your laptop, served over stdio MCP, is a complete deployment.
| Piece | What it is |
|---|---|
| Engine | The Python package and the vine CLI: the primitives, the one-shot harvest, the Gardener that ingests documents, the Ranger that keeps a forest healthy. Speaks MCP over stdio or HTTP by itself. |
| Station | The self-hostable host. Wraps the untouched engine with identity, per-forest policy, scoped grants and an audit trail, serving REST under /v1 and MCP under /mcp. |
| Studio | The web console the Station serves at /. Ask grounded questions, walk the graph, query datasets in SQL, ingest documents, grant access. It is a window: everything it shows, a client holding the same key can fetch. |
| Clipper | A Chromium browser extension that clips the page you are reading into a forest: the readable article or your selection as markdown, a screenshot or a dragged region as a media node. |
A first look
Three ways in, in rising order of ceremony: the CLI on your own machine, the engine inside your own Python, or a full Station in a container.
git clone https://github.com/JimmyWesley/MonkeyLLM.git
cd MonkeyLLM
pip install -e . # the monkeyllm package + vine CLI
vine init --forest ./brain --title "My brain" # an empty forest, git and all
vine adopt ./my-documents --forest ./brain # mirror a folder of documents in
vine serve --forest ./brain # stdio MCP, ready for any agentfrom monkeyllm import Vine
from monkeyllm.harvest import harvest
vine = Vine("./brain")
vine.plant({"id": "inbox/_index", "type": "branch", "parent": "_index",
"title": "Inbox", "summary": "Loose notes before they find a branch."})
vine.locate("where does this brain begin?") # ranked entry points, BM25, no embeddings
harvest(vine, "first note") # evidence + snippets in one call, no LLMcp .env.example .env # fill in what you use
docker compose up --build -d
# One container: REST on /v1, MCP on /mcp, and the Studio console on /.Optional extras
.docx, .xlsx and .xls ingestion needs the ingest extra (pip install -e ".[ingest]"). PDFs need a converter hook you name yourself, because a good extractor is a heavyweight and often copyleft dependency the project will not force on you. Everything else works out of the box.
Choose your path
Read Core concepts if you want the vocabulary before the code, or Hybrid retrieval if you are weighing this against the retrieval stack you already run. Otherwise, pick the surface you are building against.
Status and licensing
The engine, the Station, the Studio and the Clipper are built and measured. What follows is what the project claims and what it does not, stated the same way here as in the repository.
Two licenses
- Engine (
src/monkeyllm/, the spec, the benchmark, the tooling): Apache-2.0. The MCP contract is meant to spread. - Host (
apps/station/,apps/studio/,apps/clipper/): AGPL-3.0-only. Self-hosting is free and unrestricted. Offering it as a managed service means opening your stack. The licensing map covers the commercial option and the DCO requirement for contributions.
The benchmark, honestly
On a benchmark where every question needs at least three chained hops, the same 12B local model scores 0 out of 11 as a classic top-k RAG reader and 11 out of 11 as a forest navigator, at 0.58 times the token cost per correct answer of an iterative-RAG baseline, on a single consumer GPU.
Read this before you quote the number
The paper is a preprint. It is written and every number is reproducible from committed scripts, but it has not been deposited with a DOI yet and it has not been peer reviewed. Monkey Bench has met three of its four exit criteria; the convergence curve, which would show hops-to-answer dropping as a forest is used, has been measured once and has not met its criterion. That result is published as it stands rather than quietly dropped.
The full design, the vocabulary and every benchmark number are in the paper, and the source of everything on these pages is the repository.