Spatial context bus for AI agents. Point it at any repository and get architecture, dependency graph, churn, hot spots, and symbols -- via CLI or MCP server. No ceremony.
go install github.com/dpopsuev/locus/cmd/locus@latest{
"mcpServers": {
"locus": {
"command": "locus",
"args": ["serve"]
}
}
}Locus runs as a local stdio process with full filesystem access and native Go toolchain.
LLM agents need to understand codebases to make good decisions. Without structural context, they grep blindly, read files one at a time, and miss the big picture -- coupling, churn, layering, trust boundaries.
This creates three failure modes:
- Blind navigation. The agent reads files sequentially without knowing which packages matter or how they connect.
- Missing risk signals. High-churn, high-coupling components are invisible unless the agent happens to stumble on them.
- No shared vocabulary. Without a component model, the agent can't discuss architecture with the developer in structural terms.
Locus solves this by scanning any repository and producing a structured context report -- components, dependencies, symbols, churn, hot spots, nesting depth, LOC -- that agents consume through MCP tools. The agent gets the whole architecture in one call.
Locus is designed for natural language. You talk to your agent, and it calls the right MCP tools behind the scenes.
You: I just cloned this repo. What's the architecture?
Agent: (calls
codographwith actionscan_local) The project has 13 packages across 2 layers.internal/archis the core with 54 symbols and the highest churn (21 commits).internal/protocolis the gateway — everything routes through it. Here's the dependency diagram...
You: Which parts are risky to change?
Agent: (calls
analysiswith actioncoupling, viewhot_spots) Two components are in the danger zone:internal/arch(fan-in 7, churn 21) andinternal/analysis(fan-in 4, churn 16). Both are deeply depended on and change frequently. I'd add tests before touching either.
You: If I refactor internal/cache, what breaks?
Agent: (calls
analysiswith actionimpact) Blast radius is 38%. Direct dependents:internal/protocol,internal/history,cmd/locus. Transitive: everything that depends on those — 5 packages total. Risk level: medium.
You: Show me the architecture as a layer diagram with health colors.
Agent: (calls
render_diagramwith typelayers, themenatural) Here you go — 9 layers fromcmd/locusat the top tointernal/modelat the bottom. Red means high fan-in + high churn. Yellow is borderline.
Every diagram below was generated by running
locus diagram . --theme naturalon itself. Components are colored by health: green = healthy, yellow = sick (fan-in >= 3, churn >= 8), red = fatal (fan-in >= 5, churn >= 15). Re-run to update.
locus diagram . --type dependency --theme natural
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#F7FAFC', 'primaryTextColor': '#2D3748', 'primaryBorderColor': '#4A90D9', 'lineColor': '#4A90D9', 'background': '#FFFFFF', 'fontSize': '14px'}}}%%
graph TD
classDef boundary fill:#FFFFFF,stroke:#718096,color:#2D3748
classDef component fill:#F7FAFC,stroke:#4A90D9,color:#2D3748
classDef edge stroke:#4A90D9
classDef entry fill:#4A90D9,stroke:#4A90D9,color:#FFFFFF
classDef fatal fill:#E53E3E,stroke:#E53E3E,color:#FFFFFF
classDef healthy fill:#38A169,stroke:#38A169,color:#FFFFFF
classDef sick fill:#D69E2E,stroke:#D69E2E,color:#FFFFFF
classDef violation_edge stroke:#E53E3E
cmd_locus["cmd/locus [churn:15]"]:::entry
internal_analysis["internal/analysis [churn:29]"]:::fatal
internal_arch["internal/arch [churn:27]"]:::fatal
internal_cache["internal/cache [churn:5]"]:::healthy
internal_config["internal/config [churn:1]"]:::healthy
internal_cursor["internal/cursor [churn:3]"]:::healthy
internal_diagram["internal/diagram [churn:38]"]:::healthy
internal_history["internal/history [churn:8]"]:::sick
internal_mcp["internal/mcp [churn:19]"]:::healthy
internal_model["internal/model [churn:3]"]:::healthy
internal_protocol["internal/protocol [churn:22]"]:::healthy
internal_remote["internal/remote [churn:4]"]:::healthy
internal_store["internal/store [churn:11]"]:::sick
internal_survey["internal/survey [churn:31]"]:::healthy
internal_triage["internal/triage [churn:3]"]:::healthy
cmd_locus -->|"2"| internal_analysis
cmd_locus -->|"5"| internal_arch
cmd_locus -->|"1"| internal_config
cmd_locus -->|"15"| internal_diagram
cmd_locus -->|"1"| internal_mcp
cmd_locus -->|"29"| internal_protocol
cmd_locus -->|"8"| internal_triage
internal_analysis -->|"6"| internal_model
internal_analysis -->|"5"| internal_survey
internal_arch -->|"4"| internal_analysis
internal_arch -->|"22"| internal_model
internal_arch -->|"4"| internal_survey
internal_cache -->|"1"| internal_arch
internal_config -->|"2"| internal_cache
internal_config -->|"1"| internal_history
internal_config -->|"4"| internal_store
internal_diagram -->|"45"| internal_analysis
internal_diagram -->|"24"| internal_arch
internal_diagram -->|"4"| internal_history
internal_history -->|"13"| internal_arch
internal_history -->|"3"| internal_cache
internal_mcp -->|"2"| internal_analysis
internal_mcp -->|"8"| internal_arch
internal_mcp -->|"17"| internal_diagram
internal_mcp -->|"53"| internal_protocol
internal_mcp -->|"3"| internal_store
internal_mcp -->|"11"| internal_triage
internal_protocol -->|"12"| internal_analysis
internal_protocol -->|"61"| internal_arch
internal_protocol -->|"4"| internal_cursor
internal_protocol -->|"12"| internal_history
internal_protocol -->|"12"| internal_remote
internal_protocol -->|"34"| internal_store
internal_remote -->|"9"| internal_arch
internal_store -->|"5"| internal_arch
internal_store -->|"7"| internal_cache
internal_store -->|"9"| internal_history
internal_survey -->|"46"| internal_model
locus diagram . --type layers --theme natural
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#F7FAFC', 'primaryTextColor': '#2D3748', 'primaryBorderColor': '#4A90D9', 'lineColor': '#4A90D9', 'background': '#FFFFFF', 'fontSize': '14px'}}}%%
block-beta
columns 1
block:layer_0["Layer 0"]
cmd_locus["cmd/locus"]
end
columns 1
block:layer_1["Layer 1"]
internal_mcp["internal/mcp"]
end
columns 3
block:layer_2["Layer 2"]
internal_diagram["internal/diagram"]
internal_protocol["internal/protocol"]
internal_triage["internal/triage"]
end
columns 3
block:layer_3["Layer 3"]
internal_cursor["internal/cursor"]
internal_history["internal/history"]
internal_remote["internal/remote"]
end
columns 1
block:layer_4["Layer 4"]
internal_cache["internal/cache"]
end
columns 1
block:layer_5["Layer 5"]
internal_arch["internal/arch"]
end
columns 1
block:layer_6["Layer 6"]
internal_analysis["internal/analysis"]
end
columns 1
block:layer_7["Layer 7"]
internal_survey["internal/survey"]
end
columns 1
block:layer_8["Layer 8"]
internal_model["internal/model"]
end
locus diagram . --type c4 --theme natural
C4Component
title github.com/dpopsuev/locus
Container_Boundary(cmd_boundary, "cmd") {
Component(cmd_locus, "cmd/locus", "package", "1 symbols, churn 9", $tags="healthy")
}
Container_Boundary(internal_boundary, "internal") {
Component(internal_analysis, "internal/analysis", "package", "38 symbols, churn 16", $tags="fatal")
Component(internal_arch, "internal/arch", "package", "54 symbols, churn 21", $tags="fatal")
Component(internal_cache, "internal/cache", "package", "5 symbols, churn 4", $tags="healthy")
Component(internal_cursor, "internal/cursor", "package", "4 symbols, churn 2", $tags="healthy")
Component(internal_diagram, "internal/diagram", "package", "14 symbols, churn 32", $tags="healthy")
Component(internal_history, "internal/history", "package", "12 symbols, churn 8", $tags="sick")
Component(internal_mcp, "internal/mcp", "package", "1 symbols, churn 10", $tags="healthy")
Component(internal_model, "internal/model", "package", "45 symbols, churn 3", $tags="healthy")
Component(internal_protocol, "internal/protocol", "package", "27 symbols, churn 11", $tags="healthy")
Component(internal_remote, "internal/remote", "package", "6 symbols, churn 3", $tags="healthy")
Component(internal_survey, "internal/survey", "package", "12 symbols, churn 20", $tags="healthy")
Component(internal_triage, "internal/triage", "package", "6 symbols, churn 3", $tags="healthy")
}
Rel(cmd_locus, internal_analysis, "uses")
Rel(cmd_locus, internal_arch, "uses")
Rel(cmd_locus, internal_cache, "uses")
Rel(cmd_locus, internal_diagram, "uses")
Rel(cmd_locus, internal_history, "uses")
Rel(cmd_locus, internal_mcp, "uses")
Rel(cmd_locus, internal_protocol, "uses")
Rel(cmd_locus, internal_triage, "uses")
UpdateElementStyle(*, $fontColor="#2D3748", $borderColor="#4A90D9")
UpdateElementStyle(healthy, $bgColor="#38A169", $borderColor="#38A169")
UpdateElementStyle(sick, $bgColor="#D69E2E", $borderColor="#D69E2E")
UpdateElementStyle(fatal, $bgColor="#E53E3E", $borderColor="#E53E3E")
locus diagram . --type tree --theme natural— health markers: ✘ = fatal, ⚠ = sick
mindmap
root(("locus"))
cmd (1 sym)
cmd/locus (1 sym)
internal (224 sym)
✘ internal/analysis (38 sym)
✘ internal/arch (54 sym)
internal/cache (5 sym)
internal/cursor (4 sym)
internal/diagram (14 sym)
⚠ internal/history (12 sym)
internal/mcp (1 sym)
internal/model (45 sym)
internal/protocol (27 sym)
internal/remote (6 sym)
internal/survey (12 sym)
internal/triage (6 sym)
locus diagram . --type coupling --theme natural
---
config:
sankey:
showValues: true
---
%% Health legend: Healthy=#38A169 Sick=#D69E2E Fatal=#E53E3E
sankey-beta
internal/protocol,internal/arch,51
internal/survey,internal/model,46
internal/diagram,internal/analysis,45
internal/mcp,internal/protocol,44
cmd/locus,internal/protocol,28
internal/arch,internal/model,22
internal/diagram,internal/arch,21
internal/mcp,internal/diagram,15
cmd/locus,internal/diagram,15
internal/history,internal/arch,13
internal/mcp,internal/triage,11
internal/protocol,internal/remote,11
internal/protocol,internal/history,9
cmd/locus,internal/triage,8
internal/remote,internal/arch,7
internal/protocol,internal/cache,6
cmd/locus,internal/arch,5
internal/diagram,internal/history,4
internal/arch,internal/survey,4
internal/protocol,internal/cursor,4
internal/arch,internal/analysis,4
internal/history,internal/cache,3
internal/analysis,internal/survey,2
cmd/locus,internal/analysis,2
internal/protocol,internal/analysis,2
internal/mcp,internal/arch,2
internal/mcp,internal/analysis,2
cmd/locus,internal/cache,2
internal/cache,internal/arch,1
internal/mcp,internal/cache,1
internal/analysis,internal/model,1
cmd/locus,internal/mcp,1
cmd/locus,internal/history,1
These produce large output best viewed interactively. Run to generate for any repository:
locus diagram . --type zones --theme natural # architecture zones with health
locus diagram . --type classes --theme natural # class diagram with health colors
locus diagram . --type classes --exported-only # exported symbols only
locus diagram . --type er --theme natural # entity-relationship
locus diagram . --type sequence --entry ScanAndBuild # call trace from entry point
locus diagram . --type callgraph --entry ScanProject # function call graph
locus diagram . --type dataflow --entry main # DFD with trust boundaries
locus diagram . --type state # state machine detection
locus diagram . --type dependency --enrich loc,fan_in # metrics on node labels| Package | Symbols | Churn | Role |
|---|---|---|---|
cmd/locus |
1 | 9 | CLI entry point (Cobra). Every MCP tool has a CLI equivalent. |
internal/mcp |
1 | 10 | MCP server. Thin handlers that delegate to protocol. |
internal/protocol |
27 | 11 | All business logic: scan, diff, coverage, cycles, evolution. Both CLI and MCP call through this layer. |
internal/arch |
54 | 21 | Architecture model: scan, render, churn, hot spots, cycles, coverage, API surface. |
internal/analysis |
38 | 16 | Type analysis (classes, interfaces, field refs, call chains, nesting) and deep analysis (call graph, data flow, state machines). |
internal/diagram |
14 | 32 | Mermaid diagram renderers for all 12 diagram types with theming. |
internal/survey |
12 | 20 | Language-specific scanners: Go, Rust, Python, TypeScript, C/C++, LSP, ctags. |
internal/model |
45 | 3 | Data model: Project, Namespace, File, Symbol, DependencyGraph. |
internal/store |
— | new | Hexagonal storage port: Store interface + FilesystemStore adapter + LRU decorator. |
internal/config |
— | new | Backend selection and dependency wiring from env vars. |
internal/cache |
5 | 4 | Filesystem scan cache keyed by git HEAD SHA (wrapped by Store). |
internal/history |
12 | 8 | Codograph history: record, list, diff between snapshots (wrapped by Store). |
internal/remote |
6 | 3 | Shallow-clone remote repos, scan, cache by URL+SHA. |
internal/cursor |
4 | 2 | Read .cursor/rules and .cursor/skills from workspaces. |
internal/triage |
6 | 3 | Intent-to-tool routing. Pure keyword matching, no LLM. |
| Tool | Description |
|---|---|
codograph |
Scan and compare repository architectures. Actions: scan_local, scan_remote, history, diff, status, set_desired_state, get_desired_state. Use intent for scan depth (architecture/coupling/health/full). Returns cache_key for downstream tools. |
analysis |
16 analysis actions: deps, impact, coupling (view=hot_spots/edges), cycles, violations, scan_diff, callers, cross_repo, drift, suggest_architecture, search, component, preset (architecture_review/health_check/onboarding/pre_pr), query (natural language), coverage, api_surface, conventions, gaps. Pass cache_key from scan to avoid re-scanning. format=summary for <500 tokens. |
render_diagram |
13 diagram types: dependency, c4, coupling, churn, layers, tree, zones, classes, sequence, er, dataflow, callgraph, state. format=facts for plain-text assertions. enrich=loc,fan_in,churn for metrics on nodes. theme (light/dark/natural). |
triage |
Map natural language intent to ranked tool list (no LLM). |
codograph status → check what's cached
codograph scan_local → returns cache_key + 50-token summary
intent=architecture → fast structure-only scan
intent=health → default, includes churn + nesting
analysis coupling cache_key → risk areas without re-scanning
render_diagram type=zones → architecture overview
analysis drift → check against desired state
Locus includes a built-in intent router that maps natural language queries to the right tool chain without an LLM:
$ locus triage "where are the hot spots?"{
"category": "architecture",
"confidence": 0.037,
"tools": [
{
"name": "analysis",
"params": { "action": "coupling", "view": "hot_spots", "top_n": 10 },
"reason": "Structural hot spots reveal design pressure points"
}
]
}All tools grouped by category:
| Category | Tools |
|---|---|
| architecture | codograph scan_local, analysis coupling, codograph scan_remote, analysis, render_diagram |
| onboarding | codograph scan_local, codograph scan_remote |
| performance | analysis coupling (view=hot_spots), analysis |
| refactoring | analysis coupling (view=hot_spots), analysis deps, analysis impact |
| dependencies | analysis deps, analysis coupling (view=edges), analysis |
| comparison | codograph history (diff=true), codograph diff |
| review | codograph diff |
| churn | codograph history |
| testing | analysis (analysis=coverage) |
| quality | analysis (analysis=gaps) |
| security | analysis (analysis=api_surface) |
| visualization | render_diagram |
| meta | triage |
| Language | Scanner | Symbols | Dependencies |
|---|---|---|---|
| Go | go/ast native |
functions, types, methods, interfaces | import graph + call graph (GoAST analyzer) |
| Rust | Cargo.toml + regex | functions, structs, traits, impls | crate dependency graph |
| Python | tree-sitter-python | functions, classes, async functions | import graph + call graph (PythonDeep analyzer) |
| TypeScript | tree-sitter-typescript | functions, classes, arrow functions | import graph + call graph (TypeScriptDeep analyzer) |
| C/C++ | #include + ctags |
functions, structs, typedefs | include graph |
| Any | LSP (gopls, etc.) | workspace/symbol | references |
| Any | ctags (universal) | all ctags kinds | import heuristics |
Locus supports three visual themes for Mermaid diagrams: light, dark, and natural (default). Themes control colors, shapes, and health-based semantic coloring.
Components are automatically classified by risk level based on fan-in and churn:
| Level | Condition | Color |
|---|---|---|
| Healthy | Default | Green |
| Sick | fan-in >= 3 AND churn >= 8 | Yellow |
| Fatal | fan-in >= 5 AND churn >= 15 | Red |
Health coloring is applied to dependency flowcharts, C4 component diagrams, churn bar charts, and tree mindmaps. Layer diagrams highlight violations in red.
locus diagram . --type dependency --theme dark
LOCUS_THEME=dark locus diagram . --type c4Via MCP: pass "theme": "dark" in the render_diagram arguments.
Place a theme.yaml in ~/.locus/ or set LOCUS_THEME_FILE to override default tokens:
colors:
green:
dark: "#68D391"
light: "#276749"
natural: "#38A169"
shapes:
component:
fill: surface
stroke: blue
color: text| Variable | Default | Description |
|---|---|---|
LOCUS_STORE |
filesystem |
Storage backend: filesystem |
LOCUS_CACHE_DIR |
~/.locus/cache |
Scan cache directory |
LOCUS_HISTORY_DIR |
~/.locus/history |
Codograph history directory |
LOCUS_TRANSPORT |
stdio |
Transport: stdio, http |
LOCUS_ADDR |
:8081 |
Listen address (HTTP only) |
LOCUS_THEME |
natural |
Default diagram theme: light, dark, natural |
LOCUS_THEME_FILE |
~/.locus/theme.yaml |
Custom theme override file |
LOCUS_LOG_LEVEL |
info |
Log level: debug, info, warn, error. JSON to stderr. |
MIT
