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
605KB
16K
SLoC
charter πΊοΈπ
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
MCP Server (recommended for AI agents)
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::WalkParallelcollects all.rsand.pyfiles- Cache check: match
(path, size, mtime)or blake3 hash tree-sitterparses each file with thread-local parser pool (Rust or Python grammar)- Extract: symbols, imports, complexity, call graph, error propagation
JoinSetcollects 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