#llm-context #parser #llm #ast

bin+lib charter

Fast structural context generator for Rust codebases, optimized for LLM consumption

4 releases

Uses new Rust 2024

0.1.3 Feb 7, 2026
0.1.2 Feb 6, 2026
0.1.1 Feb 4, 2026
0.1.0 Feb 4, 2026

#1097 in Command line utilities

MIT/Apache

605KB
16K SLoC

charter πŸ—ΊοΈπŸŒ

github crates.io license

Token-dense structural context for LLMs, in seconds.

cargo install charter

charter generates a .charter/ directory containing token-dense structural context for Rust and Python codebases.

When you're working with an LLM that's lost track of your codebase (after context compaction, or in a new session), charter read provides the structured context it needs to re-orient: symbol locations, call graphs, type flows, semantic clusters, and more.

Compresses your codebase into structured, token-efficient context β€” typically 60-70% smaller than raw source while preserving full structural coverage.

Installation

cargo install charter        # from crates.io
cargo install --path .       # from source

Quick Start

# In your Rust or Python project root:
charter              # Generate .charter/ directory
charter read         # Output context to stdout

That's it. Run charter once to capture, then charter read whenever you need to reload context. Charter automatically detects whether your project is Rust, Python, or mixed.

Commands

charter

Generates or updates the .charter/ directory. Incremental β€” only re-parses files that changed.

$ charter

Charter @ a3f8c2d β†’ b7e1d4f | 3 modified, 1 added, 0 removed

  modified: src/ecs/query.rs (+2 symbols, signature changed: fn execute)
  modified: src/render/pipeline.rs (fields changed on RenderState)
  added: src/render/postprocess.rs (14 symbols)

Captured @ b7e1d4f (316 files, 89,421 lines)
  parsed: 4, cached: 312, skipped: 0

charter read [tier]

Outputs structural context to stdout. Three tiers control verbosity:

Tier Contents Use when
quick overview + types + hotspots Orientation and API surface
default quick + dependents + clusters + calls Normal usage
full default + symbols + dataflow + manifest + safety + errors Deep analysis
charter read          # default tier
charter read quick    # minimal
charter read full     # everything

Options:

  • --focus <path> β€” Filter output to a specific directory or file
  • --since <ref> β€” Show changes since a git ref (marks files with [+] added, [~] modified, [-] deleted)
charter read --focus src/pipeline    # Only show src/pipeline/**
charter read --since HEAD~5          # Highlight changes in last 5 commits

charter lookup <symbol>

Look up a single symbol with full context:

$ charter lookup PipelineResult

PipelineResult [struct] defined at src/pipeline.rs
  pub struct PipelineResult {
    pub files: Vec<FileResult>,
    pub workspace: WorkspaceInfo,
    pub git_info: Option<GitInfo>,
    pub total_lines: usize,
    pub skipped: Vec<SkippedFile>,
    pub diff_summary: Option<DiffSummary>,
  }

  Derives: Debug, Default
  Referenced in 12 files:
    src/output/calls.rs, src/output/clusters.rs, src/output/dataflow.rs, src/output/dependents.rs

charter query "<query>"

Search for symbols, relationships, and patterns:

charter query "callers of write_calls"     # What functions call write_calls?
charter query "callees of capture"         # What does capture() call?
charter query "implementors of Default"    # What types implement Default?
charter query "users of Cache"             # What files use the Cache type?
charter query "errors in pipeline.rs"      # Error propagation in a file
charter query "hotspots"                   # High-complexity functions
charter query "public api"                 # Public symbols only

charter deps [--crate <name>]

Analyze external dependency usage:

$ charter deps --crate tokio

tokio (version from Cargo.toml)
  Used in 12 files, 47 imports

  Items used:
    fs::read_to_string (8 files)
    sync::Mutex (5 files)
    task::spawn (4 files)
    ...

charter tests [--file <path>]

Map tests to source files:

$ charter tests --file src/cache.rs

Tests covering src/cache.rs:
  tests/cache_tests.rs
    test_cache_load
    test_cache_save
    test_cache_invalidation

charter session start|end|status

Track what changed during a work session:

charter session start    # Mark session start
# ... do work ...
charter session status   # See what changed
charter session end      # End session tracking

charter serve [path]

Starts an MCP (Model Context Protocol) server over stdio. The server scans the codebase on startup and holds the parsed index in memory, exposing 12 tools for structural queries. All tools return structured JSON.

charter serve           # serve current directory
charter serve /path     # serve a specific project

MCP Tools:

Tool Parameters Description
search_symbols query, kind?, limit? Fuzzy/partial search across all symbols
find_symbol name, kind? Exact or fuzzy lookup of a specific symbol
find_implementations symbol Trait implementors, type methods, derive-generated impls
find_callers symbol All call sites with caller name, file, and line
find_dependencies symbol, direction Upstream/downstream/both dependencies with file:line
get_module_tree root? File paths with symbol counts
get_type_hierarchy symbol Trait inheritance, derives, supertraits, base classes
summarize scope? Architectural summary with counts and complexity hotspots
get_snippet name Captured function bodies with importance scores
read_source file, start_line, end_line? Read any source range from indexed files
search_text pattern, glob?, case_insensitive?, context_lines?, max_results? Regex text search across indexed files with context
rescan β€” Re-scan codebase and persist cache

MCP client configuration (e.g. for Claude Desktop or Claude Code):

{
  "mcpServers": {
    "charter": {
      "command": "charter",
      "args": ["serve", "/path/to/project"]
    }
  }
}

charter status

Quick summary without full context output:

$ charter status
  files: 316
  lines: 89,421
  captured: 2025-01-31T14:23:07Z
  commit: a3f8c2d

Output Files

The .charter/ directory contains structured context optimized for LLM consumption:

Core Files

File Contents Example
overview.md Workspace structure, module tree, entry points, features Crate hierarchy, Python packages, bin/lib targets
symbols.md Complete symbol index with full signatures Structs, enums, functions, traits, classes
types.md Trait definitions, impl map, derive map; Python Protocols, ABCs, class hierarchy Default -> [Cache, Config, State]
refs.md Cross-reference index PipelineResult used in 12 files
dependents.md Inverse dependency map What breaks if you change a file

Analysis Files

File Contents Example
calls.md Call graph + reverse call graph node_text has 47 callers
clusters.md Semantic function groupings 87 parse functions work together
dataflow.md Type flow tracking Cache produced by X, consumed by Y
hotspots.md High-complexity functions Ranked by cyclomatic complexity + churn
errors.md Error propagation patterns Where errors originate (Result/Option, raise/assert), how they flow
safety.md Unsafe blocks, panic points, async patterns; Python dangerous calls (eval, exec, subprocess, pickle) Safety-critical code locations
snippets.md Captured function bodies Important function implementations
manifest.md File manifest with roles and churn [source] [test] [churn:high]

Internal Files

File Purpose
cache.bin Incremental update cache
meta.json Capture metadata (timestamp, commit, file count)
FORMAT.md Format specification for the output files

The .charter/ directory is auto-gitignored.

Output Format Examples

symbols.md

src/cache.rs [35 lines] [source] [churn:med]
  pub struct Cache { entries: HashMap<String, CacheEntry> }
    impl Cache:
      pub fn load(path: &Path) -> Result<Self>
      pub fn save(&self, path: &Path) -> Result<()>
      pub fn get(&self, path: &str) -> Option<&CacheEntry>

calls.md β€” Call Map

## Call Map

src/pipeline.rs [12 functions, 87 calls]
  capture β†’ emit_outputs.await?, run_phase1_with_walk.await?, build_cache
  process_file β†’ parse::parse_rust_file?, read::read_file.await?

calls.md β€” Reverse Call Graph (Callers)

## Callers

node_text [47 callers]
  extract_struct (src/pipeline/parse.rs:151)
  extract_enum (src/pipeline/parse.rs:202)
  extract_function (src/pipeline/parse.rs:465)
  [+44 more]

clusters.md

## Cluster 1: parse operations (87 functions)

src/pipeline/parse.rs:
  extract_struct (line 151)
  extract_enum (line 202)
  extract_function (line 465)
  ...

Internal calls: 234, External calls: 45

dataflow.md

## Type Flows

PipelineResult
  produced by: capture (src/pipeline.rs:135)
  consumed by: emit_outputs, write_calls, write_clusters [+35 more]

Cache
  produced by: build_cache (src/pipeline.rs:503)
  consumed by: process_file, quick_change_check_sync

hotspots.md

## High Importance

parse_rust_file [score: 89] (src/pipeline/parse.rs:73)
  cyclomatic: 12, lines: 156, calls: 47, public
  Called by: process_file

extract_items [score: 67] (src/pipeline/parse.rs:129)
  cyclomatic: 8, lines: 89, calls: 23

Staleness Detection

If files have changed since capture, charter read warns you:

⚠ 3 files changed since capture (a3f8c2d β†’ b7e1d4f):
  M src/ecs/world.rs
  M src/render/pipeline.rs
  A src/render/postprocess.rs

Structural context below may be inaccurate for these files. Read them directly for current state.

Preamble

Every charter read includes a project-specific preamble:

[charter @ a3f8c2d | 2025-01-31T14:23:07Z | 316 files | 89,421 lines]

Rust workspace with 4 crates. Primary: my-engine (lib).
Entry points: my-app (bin), 12 examples, 3 benches

Top traits by impl count:
  Component (34 impls), System (12 impls), State (6 impls)

Most-depended-on files:
  src/lib.rs (56), src/ecs/world.rs (47), src/math/vec3.rs (38)

Top referenced types:
  Entity (89), Transform (67), Handle (45)

High-churn files:
  main.rs, pipeline.rs, widgets.rs

LLM Integration

Add charter as an MCP server in your client configuration. This gives your LLM direct access to structural queries without needing to parse text output:

{
  "mcpServers": {
    "charter": {
      "command": "charter",
      "args": ["serve", "."]
    }
  }
}

The MCP server holds the full parsed index in memory and responds to queries in sub-millisecond time. Use rescan to pick up changes without restarting.

CLI (for context recovery)

Add this to your project's CLAUDE.md, AGENTS.md, or equivalent:

## Codebase Context

This project uses charter for structural context recovery. After context compaction or in a new session, if you've lost track of codebase structure:

1. Run `charter read` to reload orientation, types, and complexity hotspots
2. Use `charter lookup <Symbol>` for specific type/function/class details
3. Use `charter query "callers of X"` to trace relationships

The `.charter/` directory contains pre-computed analysis that's expensive to reconstruct from source: trait hierarchies (Protocols/ABCs for Python), call graphs, semantic clusters, and complexity rankings.

Performance

Operation 500 files 5000 files
Cold capture < 3s < 15s
Warm (0 changes) < 100ms < 100ms
Warm (10 changes) < 500ms < 500ms
charter read < 50ms < 50ms

How It Works

Phase 1 β€” Parallel Capture:

  • ignore::WalkParallel collects all .rs and .py files
  • Cache check: match (path, size, mtime) or blake3 hash
  • tree-sitter parses each file with thread-local parser pool (Rust or Python grammar)
  • Extract: symbols, imports, complexity, call graph, error propagation
  • JoinSet collects results in parallel

Phase 2 β€” Reference Resolution:

  • Build PascalCase symbol table from Phase 1
  • Match identifier locations against symbol table
  • Write cross-references with no additional I/O

License

Dual-licensed under MIT (LICENSE-MIT) or Apache 2.0 (LICENSE-APACHE).

Dependencies

~34–50MB
~1M SLoC