Skip to content
Canopy is in pre-release. These docs describe the product at its public launch — commands, tool names, and integration examples reflect what you'll see once binaries ship. Join the waitlist →

How Canopy Works

Your repo (files on disk)
│
▼ canopy index
┌─────────────────────────────────────┐
│ Indexing pipeline │
│ │
│ 1. File scanner │
│ Walk the tree; honor .gitignore │
│ and .canopyignore │
│ │
│ 2. AST symbols (tree-sitter) │
│ Every declaration across 55+ │
│ languages and formats │
│ │
│ 3. Import graph │
│ Imports resolved to target │
│ files — a directed graph │
│ │
│ 4. Tantivy full-text index │
│ camelCase-aware chunk search │
│ │
│ 5. Vector embeddings │
│ Semantic search over chunks │
│ │
│ 6. Git ingest (auto when .git/) │
│ History for ownership answers │
│ │
│ 7. Tier-A file summaries │
│ Optional: --with-summaries │
└─────────────────────────────────────┘
│
▼ stored locally in ~/.canopy/
│
▼ canopy serve (MCP stdio, --watch)
┌─────────────────────────────────────┐
│ One tool: canopy_answer │
│ │
│ question → deterministic router │
│ → one recipe │
│ → whole chain server-side │
│ → one compact answer │
└─────────────────────────────────────┘
│
▼ one tool call
AI agent (Claude Code, Cursor, …)

Two phases: build the index once, then answer questions against it. The per-question cost is a lookup, not a re-scan of the source tree.

canopy index is incremental by default — first run processes everything, later runs re-process only changed files. canopy index --full rebuilds from scratch. (canopy setup runs the first index for you.)

The index has five layers:

LayerWhat it holdsBuilt
AST symbolsEvery declaration — functions, classes, structs, types, exports — with file, line span, and signature, extracted via tree-sitter across 55+ languages and formatsAlways
Import graphImport statements resolved to their target files, stored as directed edgesAlways
Full-text (Tantivy)Code chunks with camelCase-aware tokenization: payment matches processPaymentBy default (--no-search opts out)
Vector embeddingsSemantic search over chunks, powered by a local ONNX model or OllamaBy default (--no-embeddings opts out)
Git dataCommit history for ownership and churn answersAuto when .git/ is present (--with-git forces, --no-git skips)

--with-summaries adds an optional sixth layer: Tier-A file summaries, embedded alongside the chunks. Summaries are heuristic (offline) by default; cloud backends are opt-in.

Everything lands under ~/.canopy/ — a SQLite database for symbols, graph, and git data, plus the Tantivy and vector indexes. Nothing is written into your repo, and nothing leaves the machine.

canopy serve starts the MCP server — JSON-RPC 2.0 over stdio, launched as a subprocess by your agent. With --watch, it re-indexes changed files as you edit, so answers track the working tree. The server exposes exactly one tool: canopy_answer.

Each call runs the same path:

  1. Route. A deterministic classifier maps the question to one recipe — no LLM, no network, 360/360 on its labelled regression corpus. Phrasing picks the recipe: the router keys on the entity type you name and on backticked paths and symbols.
  2. Execute. The recipe runs the whole retrieval chain server-side: symbol lookup, graph traversal, full-text or semantic retrieval, ranking, formatting. What used to be a multi-tool orchestration problem for the agent is a single internal pipeline.
  3. Answer. One compact, structured answer comes back — or an honest “No strong match in this repository for …” when nothing clears the relevance floor.

The agent makes one call and relays the result. That single-call design is the measured lift: +76% correctness at −69% tokens versus the shell grep/read loop, while a control agent orchestrating the old multi-tool catalog spent 2.3×–5.8× more than shell.

The same path is available without an agent: canopy answer "<question>" from the terminal, repo auto-detected from the current directory.

  • Local index, local queries — no latency, no authentication, no network dependency for answers.
  • One static binary — no Node.js, no Python, no daemon to manage.
  • Incremental index — re-indexing fits inside a normal development loop.

Each machine has its own index; Team tier adds a CI index cache for sharing built indexes across CI runs.