Skip to main content
Glama
README.md
# codeatlas

Turn a Python codebase into a queryable knowledge graph — for AI agents and
for humans. Point `codeatlas` at a directory of `.py` files and it builds an
**atlas**: every module, class, and function as a node, and the imports,
inheritance, and calls between them as edges. Query the atlas from the
command line, render the module map as a Mermaid diagram, or serve it to an
LLM agent over MCP so the agent can answer "who calls this?" without reading
the whole repository.

Zero third-party dependencies. Python ≥ 3.10. The only parser is the standard
library's `ast` module — your code is analysed, never executed.

## Quickstart

```bash
pip install .

codeatlas build path/to/project -o atlas.json
codeatlas stats atlas.json
codeatlas search atlas.json login
codeatlas query atlas.json myapp.auth.login --callers
codeatlas map atlas.json --out graph.mmd
codeatlas mcp atlas.json        # serve the atlas to an agent over stdio
```

No-install use from a checkout:

```bash
PYTHONPATH=src python -m codeatlas build path/to/project
```

## What goes into the atlas

`atlas.json` is plain JSON, easy to diff, grep, or feed to other tools:

```json
{
  "nodes": [
    {"id": "shop.orders.DiscountedOrder", "kind": "class",
     "file": "shop/orders.py", "line": 14,
     "docstring_first_line": "An order with a loyal-customer discount."}
  ],
  "edges": [
    {"src": "shop.orders", "dst": "shop.pricing", "kind": "imports"}
  ],
  "stats": {"files": 3, "nodes": 9, "edges": 5,
            "nodes_by_kind": {"class": 2, "function": 4, "module": 3},
            "edges_by_kind": {"calls": 3, "imports": 1, "inherits": 1}}
}
```

Node ids are dotted paths: `package.module.Class.method`. Node kinds are
`module`, `class`, and `function` (methods are functions under their class).
Edge kinds are `imports`, `inherits`, and `calls`.

## Commands

| Command | What it does |
|---|---|
| `codeatlas build <path> [-o atlas.json]` | Scan a directory (or single file) and write the atlas |
| `codeatlas query <atlas> <symbol> [--callers\|--callees\|--imports]` | Show a symbol, or one relationship as a list |
| `codeatlas search <atlas> <term>` | Substring search over symbol ids and docstrings |
| `codeatlas map <atlas> [--out graph.mmd]` | Mermaid flowchart of module-level imports |
| `codeatlas stats <atlas>` | Files / nodes / edges, broken down by kind |
| `codeatlas mcp <atlas>` | Stdio MCP server (see below) |

Symbols in `query` do not need to be full ids: an exact id wins, then a
unique dotted suffix, then a simple name.

## MCP server mode

`codeatlas mcp atlas.json` runs a small stdio JSON-RPC MCP server
(`initialize`, `tools/list`, `tools/call`) with four tools:

- `search_symbols` — find symbols by substring
- `callers_of` — who calls a symbol
- `callees_of` — what a symbol calls
- `module_deps` — what a module imports, and what imports it

Wire it into any MCP-speaking agent and the agent can navigate the codebase
structurally — impact analysis before an edit, orientation in an unfamiliar
repository — instead of guessing from filenames.

## How resolution works (honestly)

Static, name-based analysis has limits. codeatlas uses these heuristics:

- **Imports** are linked only when the dotted path matches a scanned project
  module (relative imports are resolved against the importing package).
  Standard-library and third-party imports produce no edge. Imports are
  collected at module level, including inside top-level `if`/`try` blocks.
- **Inheritance** links a base class when a class with the same simple name
  (or a matching dotted suffix) exists in the project; a class from the same
  module wins.
- **Calls** link when the called name matches a project function or method:
  `self.x()` prefers a sibling method of the same class, a bare `name()`
  prefers a function in the same module, and otherwise the first matching
  name in the project wins.

That means dynamic dispatch, `getattr`, decorators that replace functions,
and coincidental same-named helpers can produce missing or wrong call edges.
Treat the atlas as a good map of the territory — not the territory.

## Self-scan

codeatlas, scanned with itself (`codeatlas build src`):

- **6 files, 51 nodes** (6 modules, 2 classes, 43 functions),
  **64 edges** (58 calls, 6 imports).

## Development

```bash
PYTHONPATH=src python -m unittest discover -s tests
```

24 tests cover the scanner (a fixture package with known imports,
inheritance, and calls), the query layer, the CLI, Mermaid output, and an
MCP round-trip driven through a subprocess.

## What is included

- `src/codeatlas/scanner.py` — directory walking and `ast` extraction
- `src/codeatlas/graph.py` — the `Atlas` model, queries, stats, Mermaid
- `src/codeatlas/cli.py` — the six subcommands
- `src/codeatlas/mcp_server.py` — the stdio MCP server
- `examples/demo_package/` — a three-module package to try it on

## Roadmap

- Cross-file type-aware call resolution
- HTML atlas viewer
- Incremental rebuilds

## License

MIT — see `LICENSE`.

TDQS

B3.1/5.0

Scored across 4 tools

Disambiguation4/5

Each tool targets a distinct operation: substring search, incoming call edges, outgoing call edges, and module-level import edges. The only mild overlap is that callers_of and module_deps both answer 'what depends on this', but the symbol-vs-module scoping in the descriptions keeps them separable.

Naming Consistency3/5

Three different naming patterns coexist: verb_noun (search_symbols), noun_of relations (callers_of, callees_of), and noun_noun (module_deps). Each name is readable and self-explanatory, but the set does not follow a single predictable convention.

Tool Count4/5

Four tools is minimal but well-scoped for a symbol-graph lookup server; every tool covers a distinct query direction with no filler. It sits at the lean end of the acceptable range rather than feeling padded or arbitrarily thin.

Completeness3/5

The graph traversal surface is coherent (search, callers, callees, imports), but there is no way to fetch a symbol's details, signature, or location, and no file-level or reference-lookup operation. Agents can navigate the graph but will hit dead ends when they need the symbol itself.

Maintenance

ActivityMaintained
ResponsivenessNo issues