enola/Docs

Documentation

Give your agent a map
before it explores.

Enola. is a local MCP server that generates compact architectural snapshots of your repository. Run it once and any MCP-compatible agent — Claude Code, Cursor, Copilot, Codex — gets a structured overview of modules, symbols, dependencies, routes, and patterns before it reads a single file.

01 · Install

Add enola. to your agent

enola is a Go binary. Build it once, point your agent's MCP config at it, and every MCP-compatible tool in your stack gets access to the architectural graph.

Install — macOS / Linux / Windowsshell
curl -fsSL https://raw.githubusercontent.com/enola-labs/enola/main/install.sh | sh
The install script puts the binary in ~/.local/bin. If that's not on your PATH, add it: export PATH="$HOME/.local/bin:$PATH"
Register with Claude Code
claude mcp add enola enola /path/to/mcp-arch.yaml
Cursor · Copilot · other MCP clientsmcp.json
{
  "mcpServers": {
    "enola": {
      "command": "enola",
      "args": ["/path/to/mcp-arch.yaml"]
    }
  }
}
Or build from sourceshell
go build -o enola ./cmd/enola

# or install globally
go install ./cmd/enola
Prebuilt binaries are available for Linux, macOS (amd64/arm64), and Windows (amd64) — no Go required. Source build prerequisites: Go 1.25+ and a C compiler (required for tree-sitter CGo bindings). The config's repo: field is only the default repository — you can still snapshot any repo by passing repo_path to generate_snapshot.

02 · Workflow

Generate first, then ask

Enola. is a first step, not a replacement for file reading. Generate the snapshot before your agent starts exploring — then every prompt in the session has the map as context.

1

Generate the snapshot

Ask your agent: "Generate an architectural snapshot of /path/to/project". This runs the full pipeline. Even large repos index in seconds.

2

Ask structural questions naturally

You don't need to reference enola explicitly. The agent reads the arch://snapshot/context resource automatically and answers from the map.

3

Regenerate after major changes

If you add packages, rename modules, or restructure directories, call generate_snapshot again. Incremental updates are fast — only changed files are re-extracted.

Example prompts: "I just joined this project — give me a tour based on the snapshot." · "What packages should I touch to add a new API endpoint?" · "What would break if I refactor internal/server?"

03 · The graph

Kinds and relations

Enola. models your codebase as a typed, directed graph. The nodes are architectural kinds — the things in your code. The edges are relations — how those things connect. Every tool operates on this graph.

Kinds (nodes)

KindWhat it represents
module

A package or directory — the coarsest grouping unit.

symbol

A function, method, struct, interface, type, class, or constant.

route

An HTTP or API endpoint — method, path, and handler.

storage

A database table or data store (e.g. ActiveRecord model, JPA entity).

dependency

An import relationship to an external or internal package.

service

A whole repository — used when analyzing multiple repos together.

Relations (edges)

RelationMeaning
declares

A module declares a symbol, route, or storage entity.

imports

One module imports another.

calls

A function or method invokes another.

implements

A type implements an interface or mixes in a module.

depends_on

A general dependency edge between any two nodes.

instantiates

A function creates an instance of a type.

injects

A DI framework provides a dependency (Hilt, Spring, constructor injection).

has_method

A class or struct owns a method — synthetic edge for traversal completeness.

Nothing in the graph is guessed by a language model. All nodes and edges derive from deterministic parsers (go/ast, tree-sitter grammars, YAML/JSON scanners) or graph algorithms (Tarjan for cycles, pattern matching for layers). Run it twice on the same commit and you get the same answer.

04 · MCP tools

What enola. exposes to agents

Once connected, your agent sees thirteen tools. Most sessions only need generate_snapshot — the traversal, insight, and diff tools handle deeper follow-ups.

ToolWhat it does
generate_snapshot

Parses the codebase and produces a structured architectural graph. Auto-detects Go, TypeScript, Kotlin, Ruby, Python, Swift, Rust, C, C++, Java, PHP, and OpenAPI from project markers — no per-language config needed. Extracts module, symbol, dependency, route, and relation facts. Pass append: true to merge multiple repositories into a single traversable graph. Pass fresh: true when switching to a different project in the same session — required to avoid silently reusing stale graph state.

query_facts

Precision filter over extracted facts. Best for targeted lookups when you know what you want. Filter by kind (module, symbol, function, class, route, dependency), name (substring), file, relation, prop, or repo. Output modes: compact (token-efficient), full (all fields), names (identifiers only). Use explore instead when you want a broad view of an entity.

explore

Primary post-snapshot navigation tool. Pass any module name, file path, symbol, or directory and get a structured markdown overview of its contents, dependencies, relations, and outbound HTTP and gRPC client calls (Retrofit, URLSession, fetch, Net::HTTP, http.Client, grpc-go, connect-go, grpc-web, connect-es, Python gRPC stubs). Accepts partial names — path normalization handles trailing slashes and relative paths. Reach for this first; use query_facts for structured filtering or traverse for deep graph walking.

show_symbol

Return source code for a named symbol. Tries exact match first, falls back to substring. Default context window: ~15 lines before, ~45 lines after the definition. Override with context_lines_before and context_lines_after. Works across multi-repo snapshots.

traverse

Walk the dependency or call graph from a starting node. direction='forward': what does X import or depend on? direction='reverse': what depends on X? Starting node accepts substring — multiple matches are grouped by match. Filter by relation kind (e.g. imports, calls, implements) or node kind (e.g. module, function). Default depth: 3.

find_path

BFS shortest path between two graph nodes. Both from and to accept substring names — if multiple nodes match, the closest pair is used. Answers "how does X reach Y?" or "what is the call chain from main to this handler?". Returns an ordered list of node → relation → node steps.

impact_analysis

Return the blast radius of a change — all nodes that transitively depend on the target, grouped by depth. Set include_forward: true to also return what the target depends on (reverse + forward in one call). Target accepts substring matching. Use before refactoring to understand risk surface.

query_insights

Retrieve computed explainer findings — coverage gaps, unused routes, architectural smells, complexity outliers — filtered by source, repo, or confidence threshold. Use after generate_snapshot to surface what the insight layer found without reading the full insights.json.

coverage_report

Return a cross-repo edge resolution summary — which outbound calls were matched to handlers in other repositories and which remain unresolved. Useful for verifying that multi-repo graphs are correctly linked before running impact analysis.

set_baseline

Pin the current snapshot as a baseline. The baseline is stored in .enola/baseline/ and persists across re-snapshots. Use before a major refactor to enable before/after comparison.

diff_snapshot

Compare the current snapshot against the pinned baseline and return a structural delta — nodes added or removed, edges changed, new cycles or layer violations introduced. Useful for verifying that a refactor produced only the intended structural changes. Guarded by a comparability check — mismatched configs or extractor versions are flagged instead of silently diffed.

snapshot_receipt

Return the receipt.json for the current snapshot — provenance metadata (enola version, git ref, content fingerprint, config hash, output hash) plus extraction-quality metrics. Use to verify exactly what a snapshot was built from before trusting its output downstream.

compare_receipts

Compare two snapshot receipts and report whether they're comparable — same config hash, extractor versions, and repo set. Run before diff_snapshot to catch mismatches that would otherwise make a structural diff misleading.

05 · Languages

Supported languages

Enola. auto-detects languages from project markers and runs the appropriate extractor. No per-language config required.

LanguageExtractorDetected by
Go

go/ast

go.mod

Java

tree-sitter AST parser

pom.xml, build.gradle, or .java files (Spring routes / JPA / Lombok DI / Dubbo SPI aware)

TypeScript / JS

tree-sitter

tsconfig.json or package.json — processes .ts, .tsx, .js, .jsx (Next.js & monorepo aware)

Vue / Nuxt

tree-sitter (TS extractor)

package.json with vue or nuxt dependency — SFC script block extraction; Nuxt file-based routes inferred from pages/

Svelte / SvelteKit

tree-sitter (TS extractor)

package.json with svelte dependency — .svelte SFC extraction; $lib alias resolved to src/lib/; SvelteKit file-based routes inferred

Python

tree-sitter AST parser

pyproject.toml, setup.py, requirements.txt, or similar (FastAPI / Django / SQLAlchemy / gRPC aware)

Kotlin

tree-sitter AST parser

build.gradle.kts, build.gradle, or pom.xml (Compose / Hilt / Room aware; falls back to a src/main/kotlin source root)

Swift

tree-sitter AST parser

Package.swift, .xcodeproj, or .xcworkspace (SwiftUI / UIKit aware)

Ruby

tree-sitter AST parser

Gemfile (Rails / ActiveRecord / Packwerk aware), or extensionless scripts with a Ruby shebang for Gemfile-less repos

C

tree-sitter AST parser

.c / .h files

C++

tree-sitter AST parser

CMakeLists.txt, .cpp / .hpp / .cc files (header/source merging, namespaces, templates)

PHP

tree-sitter AST parser

composer.json or .php files (WordPress / Laravel / Symfony aware)

Rust

tree-sitter AST parser

Cargo.toml (cross-crate and submodule resolution for Cargo workspaces, Axum route detection)

OpenAPI

YAML/JSON scanner

Any file containing openapi: or swagger:

06 · Configuration

mcp-arch.yaml

Create an mcp-arch.yaml in your repository root (or pass a custom path as the first argument to the binary). All fields are optional.

FieldDescriptionDefault
repo

Repository root path

"."

ignore

Glob patterns for files/dirs to skip

vendor, node_modules, .git, tests, build dirs, docs

extractors

Enabled extractors

All supported

explainers

cycles, layers, cross-repo, coverage, unused-routes, god-class, hotspots, dependency-depth, exported-surface, complexity-outliers

All

output.dir

Output directory for generated artifacts

".enola"

output.max_context_tokens

Token budget for the LLM context summary

16000

incremental

Reuse content-hash cache to skip unchanged files on re-snapshot

true

Minimal configmcp-arch.yaml
repo: "."
extractors:
  - go
  - typescript
  - python
output:
  dir: ".enola"
  max_context_tokens: 16000
Artifacts are written to .enola/: llm_context.md (compact architecture summary for LLM consumption), facts.jsonl (all extracted facts), insights.json (explainer findings with confidence scores), snapshot.meta.json (file hashes for incremental updates), previous/ (auto-rotated prior snapshot), and baseline/ (manually pinned snapshot via set_baseline).

07 · CLI modes

Running enola. outside an agent

Besides running as an MCP server, enola has standalone modes for use directly from the terminal.

--generate

One-shot snapshot

Build or refresh the architectural graph without starting the MCP server. Artifacts are written to the configured output.dir (default .enola/).

--explain

Human-readable report

Generate a snapshot, compute statistics over the fact graph, and print a report to stdout — no MCP server started, no artifacts written.

upgrade

Self-update

Resolve the latest GitHub release, download the matching platform artifact, verify its checksum, and atomically replace the running binary.

--help / --list

CLI reference

--help prints usage, flags, config path, examples, and MCP configuration. --list prints the exact tool catalogue the running server registers.

--status

Usage & value tracking

Reports uptime and session/lifetime call counts for the current repo, plus an estimate of the time and context saved. --status --all breaks this down across every repo enola has touched.

CLI usageshell
# One-shot snapshot (writes to .enola/)
enola --generate [config_path]

# Human-readable architecture report (no artifacts)
enola --explain [repo_path]

# Full CLI reference: usage, flags, config path, examples, MCP config
enola --help

# Print the exact tool catalogue the running server registers
enola --list

# Usage and value report for the current repo, or every repo touched
enola --status
enola --status --all

# Print the build version
enola --version

# Self-update to the latest release
enola upgrade

--explain covers seven sections: overview, architectural kinds, symbol breakdown, API & data surface, dependencies, detected architecture pattern with cycles and layer violations, and impact hotspots ranked by coupling. It also detects architectural smells — god classes, call-graph hotspots, deep dependency chains, large public surfaces, and complexity outliers. Useful for new-contributor orientation, pre-refactor audits, or quick checks without an AI agent.

Starting the MCP server also serves a read-only, auto-refreshing dashboard on a free loopback port: the same activity and value data as --status, plus snapshot and graph receipts, the cross-repo service and edge list with a node-link diagram, insights filterable by confidence, and the extraction-quality proof (coverage, unresolved routes, skipped-file and parse-error samples). Pass --no-dashboard to opt out; --status prints the dashboard URL while the server is running.

08 · Multi-repo

Cross-repository analysis

Enola. can link multiple repositories into a single traversable graph. Generate the first snapshot, then add more with append: true — the agent can follow a call from a web client all the way into the service that answers it.

Example promptsagent
# First repo
"Generate an architectural snapshot of /path/to/backend"

# Add more repos with append mode
"Generate a snapshot of /path/to/web-client with append mode"
"Generate a snapshot of /path/to/auth-service with append mode"

# Query across all three
"If I change the auth service, which other services are impacted?"

How repos are linked

enola uses five signals to connect repositories into a unified graph:

HTTP route matching

Client-role routes (outbound API calls) are matched to server-role routes by normalized path and HTTP method. A fetch("/api/users") in the frontend links to the GET /api/users handler in the backend.

gRPC route binding

Proto RPCs are modeled as routes and bound to their Go or Python server handlers via handled_by edges. grpc-go, connect-go, grpc-web, connect-es, and Python stub.Method() client call sites resolve to the same RPC across repos.

Import references

Import statements that name another repository create cross-repo dependency edges automatically.

Message-queue topics

A Kafka topic name reaching Go code via an envconfig default: tag or an env.Get("..._TOPIC", …) call is extracted as a topic fact and links a consumer to its producer by the topic's owning-service prefix — coupling that no import or HTTP call would otherwise reveal.

Shared symbols

Matching distinctive types (classes, structs, interfaces, enums) across repos are verified against the files that declare them, not just matched by name, before counting toward a link; framework-convention boilerplate (e.g. Rails' ApplicationController) and generated migration classes are excluded. A verified match with no corroborating import or HTTP call yields a non-traversable "shared code" fact rather than a graph edge — traverse and impact_analysis only follow edges that route matching, gRPC binding, or an import actually established.

Once linked, all thirteen tools work across repo boundaries. traverse, find_path, impact_analysis, and coverage_report follow edges between repositories — an impact analysis on a shared auth module surfaces dependents in every connected service, and coverage_report shows which cross-repo calls resolved and which didn't.

Every snapshot regeneration also refreshes a graph-wide receipt at ~/.enola/receipt.json — the composing repositories, each one's git commit/ref/dirty state and time since it joined the graph, plus current fact/insight counts, cross-repo services and edges, and coverage. It complements the per-repo receipt.json returned by snapshot_receipt.