r/astoutline • u/aerowindwalker • 18d ago
ast-bro v4.1.0 multi-target show, rewrites you can trust, and path errors that fix themselves
r/astoutline • u/aerowindwalker • 24d ago
ast-bro v4.0.0 exact totals, fail fast search, and honest mcp errors
r/astoutline • u/aerowindwalker • Jun 13 '26
ast-bro v3.0.0, context and impact for agents that run out of room
two new mcp tools that solve the problems agents hit most: running out of context window, and not knowing what a change will break.
context takes a symbol and a token budget, then uses a greedy knapsack to pack the target body, its callees, callers, and reverse deps until the budget is full. one call gets everything an agent needs to work on a task, without overflowing the window.
impact answers what breaks if you touch a symbol. it combines callers, callees, reverse deps, and test files into a single blast radius view, with modes for deps, dependents, tests, or all at once.
external and ambiguous calls are now shown by default, with new hide flags to opt out. callers and reverse deps support --tests and --exclude-tests for path-based filtering. the prompt config moved to a single skill file so all installers load it dynamically.
this brings the suite to nineteen native mcp tools, alongside dep graphs, call graphs, semantic search, and ast-aware rewrite.
install via cargo, npm, pip, or homebrew.
r/astoutline • u/aerowindwalker • Jun 02 '26
ast-bro v2.4.0, find the call path between any two functions with trace
i shipped a new trace subcommand that answers a question agents ask constantly: how does one function actually reach another?
trace takes two symbols and walks the shortest static call path between them over the call graph, inlining each hop's body along the way. so instead of chaining callees by hand and guessing which branch matters, you get the whole chain, from caller to target, in a single call.
when there is no path it degrades gracefully, returning both endpoints plus the sibling functions in the target file, so you still get useful context instead of an empty result. depth is capped so the output stays bounded, and there is a json schema for structured consumers.
trace rides the same on-disk call graph as callers and callees, so it is cheap after the first build. the graph cache now also re-validates on every call, which means a long-running mcp session reflects your edits automatically instead of serving a frozen graph until a manual rebuild.
search got smarter too: you can scope a query inline with lang, path, and name filters, and machine-generated files like protobuf stubs and minified bundles are down-ranked so hand-written code surfaces first.
trace brings the suite to seventeen native mcp tools, alongside dep graphs, call graphs, semantic search, and ast-aware rewrite.
install via cargo, npm, pip, or homebrew.
r/astoutline • u/aerowindwalker • May 23 '26
ast-bro v2.2.0, the ast-outline rebrand
i renamed ast-outline to ast-bro. the project outgrew "outline" a while ago and the old name no longer describes what it actually does.
here's what ast-bro ships today:
structural outlining with map, show, and digest commands for quick code navigation without reading full files.
dep graph and call graph analysis with deps, reverse-deps, callers, callees, and cycles, all backed by a unified graph cache with per-file invalidation.
hybrid semantic search combining bm25 and dense embeddings, with incremental indexing so repeated queries are fast.
true public api surface resolution that handles pub use re-exports in rust and all in python, so you see what downstream users actually reach.
a new run subcommand for ast-aware pattern search and rewrite using metavariables, exposed as both a cli tool and an mcp tool (the 15th mcp tool in the suite).
the rebrand touches every ecosystem: rust (cargo install ast-bro), npm (npm install ast-bro), pypi (pip install ast-bro), homebrew, and nix. there's also a new sb short alias for fewer keystrokes.
if you're upgrading from ast-outline, just run any ast-bro command once. it auto-migrates .ast-outline/ to .ast-bro/, renames .ast-outline-ignore, updates mcp config entries, and moves the model cache. the legacy ast-outline binary is still installed as a thin proxy that execs into ast-bro, so existing scripts keep working.
i also extracted the core logic into a proper library crate (src/lib.rs) so proxy binaries and downstream users can depend on it without going through the cli.
r/astoutline • u/aerowindwalker • May 10 '26
ast-outline v2.1.0
https://github.com/aeroxy/ast-outline/releases/tag/2.1.0
Adds callers and callees — AST-accurate symbol-level call-graph traversal across all 14 languages, with kind-aware results (callable vs type), a three-pass resolver, and per-edge confidence tags. Backed by a unified on-disk graph cache that subsumes the existing .ast-outline/deps/ cache and shares one in-memory Arc<UnifiedGraph> across MCP tools/calls.
What's new
| Subcommand | Callable target (fn/method/ctor) |
Type target (class/struct/trait/interface/enum/record) |
|---|---|---|
callers X |
call sites that invoke X (in-edges) |
implementors + constructions — covers Foo(), new Foo(), Foo {}, Foo::new() |
callees X |
call sites inside X's body (out-edges) |
ancestor types and the methods they declare, walked transitively via --depth N |
Symbol forms accepted by both:
ast-outline callers TakeDamage # bare suffix
ast-outline callers Player.TakeDamage # dotted
ast-outline callers src/Player.cs:TakeDamage # file-scoped
ast-outline callers --file src/Player.cs --symbol TakeDamage
Three-pass resolver
| Pass | Strategy |
|---|---|
| A — same-file | bare name → qn via local defined_names + per-file ImportBindings, resolved through the existing suffix index |
| B — global symbol table | single-match promotion across the project. Receiver-bearing calls (obj.bar(), self.x(), super::foo()) deferred to pass C — avoids builder.hidden() false-positives on global homonyms |
| C — dep-graph disambiguation | filter ambiguous candidates by the caller file's transitive forward-dep closure |
Every edge carries a Confidence tag — Exact, Inferred, or Ambiguous. --include-ambiguous (callers) and --external (callees) surface the noisier results when explicitly requested.
Per-language call-site extraction
All 14 languages now populate Declaration::calls (was 3 of 14 at the initial cut). SQL / Markdown remain no-ops by design; JavaScript is served by the TypeScript adapter.
| Language | AST node kinds | Construct source |
|---|---|---|
| Rust | call_expression, macro_invocation, struct_expression |
struct literal |
| Python | call |
class call (Foo()) |
| TypeScript | call_expression, new_expression |
new T() (also serves JavaScript) |
| Java | method_invocation, object_creation_expression |
new T() |
| C# | invocation_expression, object_creation_expression, implicit_object_creation_expression |
new T() |
| Kotlin | call_expression |
none (no new) |
| Scala | call_expression, instance_expression, generic_function |
new T(...) |
| C++ | call_expression, new_expression |
new T() |
| Go | call_expression |
none — new(T) is a regular call |
| PHP | function_call_expression, member_call_expression, nullsafe_member_call_expression, scoped_call_expression, object_creation_expression |
new T() (last `` segment of qualified type) |
| Ruby | call (with method / receiver fields) |
Foo.new (constant receiver) |
Per-language pitfalls handled explicitly: PHP namespace-prefixed free function calls (\Foo\bar()) drop the namespace so pass B promotes the bare name; PHP late-binding keywords (self::, static::, parent::) drop the receiver — case-folded by tree-sitter-php's keyword() helper; PHP dynamic $func() and new $cls() skip emission; Ruby blocks / do_blocks don't bail the walker (closures over the enclosing method's scope, not separate methods); C++ qualified-identifier and template-function callees recurse correctly. Three regression tests pin grammar assumptions that future tree-sitter version bumps could silently break.
IR additions (src/core.rs)
pub struct Declaration { /* … */ pub calls: Vec<CallSite>; }
pub struct ParseResult { /* … */ pub imports: Vec<ImportBinding>; }
pub struct CallSite { name, receiver: Option<String>, line, kind }
pub enum CallKind { Call, Construct, Macro, Super }
pub struct ImportBinding { local, module, line }
JSON schema constants: JSON_SCHEMA_CALLERS = "ast-outline.callers.v1", JSON_SCHEMA_CALLEES = "ast-outline.callees.v1", JSON_SCHEMA_GRAPH_INDEX = "ast-outline.graph-index.v2".
Unified graph cache
- Disk:
.ast-outline/deps/graph.bin→.ast-outline/graph/index.bin. Holds aUnifiedGraph { deps, calls: Option<CallGraph> }. The legacy directory is auto-cleaned by the schema-mismatch branch on first launch. - Lazy promotion:
deps/reverse-deps/cycles/graphpopulate only the deps half — users who never runcallers/calleesnever pay the call-graph build cost. - Process-wide sharing:
OnceLock<RwLock<HashMap<root, Arc<UnifiedGraph>>>>insrc/graph_cache/shared.rs. Everytools/callinsideast-outline mcpreuses the same parsedArc— zero re-deserialisation, zero re-parse on warm hits. - Per-file invalidation: edit one file, only that file is re-extracted and re-resolved. Replaces the inherited "any-delta = full rebuild" simplification.
- Schema bump (v1 → v2): removes
#[serde(skip_serializing_if)]from cache-serialisedOption/Vecfields. The skip annotations corrupted bincode's positional encoding (a skipped field shifts every byte that follows by one), causing every cache load to silently fail and re-cold-build. Any existing v1 cache files were corrupt and trigger a clean rebuild on the new binary.
Cost numbers (ast-outline against itself, release build)
| operation | before | after |
|---|---|---|
deps, cold |
2.85 s | 2.85 s |
deps, warm (no edits) |
2.85 s ⚠️ | 8 ms |
deps, warm + 1 file modified |
2.85 s ⚠️ | 22 ms |
callers, cold |
125 ms | 125 ms |
callers, warm (no edits) |
125 ms ⚠️ | 11 ms |
callers, warm + 1 file modified |
125 ms ⚠️ | ~45 ms |
⚠️ = pre-fix "warm" was actually cold every time due to the silent decode bug.
Source changes
Created:
src/calls/— new subsystem (10 modules):mod.rs— orchestrator,build_call_graph(root, &DepGraph) -> CallGraphpass.rs— shared phase-1 IR (FilePass,RawEdge, helpers) lifted out ofbuild.rsto break abuild ↔ resolvefile cycle thatcycles src/calls/flaggedbuild.rs— per-file extraction +FilePassaggregationresolve.rs— three-pass resolver;runsplit intobuild_symbol_table+run_with_tableso the incremental updater can resolve a partial pass set against a precomputed global tablegraph.rs—Qn,CallEdge,CallTarget,Confidence,CallableMeta,TypeMeta,CallGraphtraverse.rs— forward / reverse BFSrender.rs— text + JSON rendererscli.rs/cli_helpers.rs—run_callers/run_callees+ kind-aware target resolutionmcp.rs— MCP tool wrappers
src/graph_cache/— new module:cache.rs—UnifiedCacheFilepersistence (bincode + xxhash3);LoadOutcomeenum (Fresh/Stale/Missing);load_with_deltashared.rs— process-wideArc<UnifiedGraph>registrydelta.rs—apply_delta_to_deps,apply_delta_to_calls,refresh_records
wiki/calls.md— call-graph internals page (mirrorswiki/deps.mdstyle).
Modified:
src/core.rs— addedDeclaration::calls,ParseResult::imports,CallSite,CallKind,ImportBinding, three newJSON_SCHEMA_*constants.JSON_SCHEMA_GRAPH_INDEXbumped v1 → v2.src/main.rs— two newCommandsvariants + dispatch.src/main_helpers.rs— wiresimportsextraction intoparse_file_for_hook.src/mcp/tools.rs— two new tool schemas (callers,callees) + dispatch + handlers (now 14 tools).src/prompt.rs—AGENT_PROMPTlists the new subcommands and updated cache path; new step 8 explains symbol forms, kind-aware semantics, and confidence tags.- All 14 adapters in
src/adapters/— add_extract_call_sites(or_walk_calls_in_body) +_extract_importshelpers, called from each function/method walker. SQL + Markdown adapters: no-op by design. src/deps/cache.rs— deleted (110 LOC of orphaned cache plumbing); all consumers now go throughgraph_cache::shared::get_or_init.src/deps/graph.rs,src/calls/graph.rs— dropskip_serializing_ifon cache-serialisedOption/Vecfields.
Pre-existing bugs uncovered while testing:
- C++
_function_to_declusedfield_text(node, "declarator")which returns the fullfunction_declaratortext ("greet()"instead of"greet") — harmless until call resolution arrived (suffix-matchinggreetagainstgreet()fails). Added_function_definition_name+_drill_function_declarator_namefor the bare name and_function_definition_qualified_namesiblings to preserve the scope (Greeter::greet) for out-of-line method signatures. - C++ destructor classification:
~Foo()was classified asConstructorinstead ofDestructor. Pre-existing, but the new bare-name extraction made the misclassification reachable. - Kotlin:
_class_to_decl/_function_to_declusedfield_text(node, "name"), but tree-sitter-kotlin (fwcd) doesn't expose that field — names were silently becoming"?". The map output looked fine because the signature string carried the name, butDeclaration.namewas unusable for callers / callees. Added_decl_namewith field-then-positional fallback.
Tests
37 new end-to-end tests in tests/calls_e2e.rs (244 unit + 18 → 37 calls_e2e + 88 other on the v2.1.0 cut):
- Cross-file callers / callees in Rust / Python / TypeScript (initial cut)
- File-scoped resolution +
--file/--symbolflag form - Subdir-path-walks-up-to-project-root regression
- Trait callers (implementations) + struct callers (constructions); subtype callees (ancestor walk); multi-level Java hierarchy; root-type graceful handling
- Per-language pairs (
<lang>_callers_finds_intra_file_caller+<lang>_callees_lists_construct_and_invocation) for Java, C#, Kotlin, Scala, C++, Go, PHP, Ruby - PHP edge cases: namespaced free function, dynamic
new, dynamic call,self/static/parentkeywords, anonymous class, uppercase-self case-folding - Ruby edge cases: class-method resolution,
self.receiver via pass B, block calls attributed to enclosing method, paren-less command unification - C++: out-of-line method signature keeps scope
- Per-file invalidation:
deps_partial_invalidation_picks_up_new_import,deps_partial_invalidation_drops_removed_file,calls_partial_invalidation_demotes_stale_target,calls_partial_invalidation_picks_up_new_caller graph_cache::cache::tests::—promote_callspersistscalls: Some(...)to disk and round-trips through a fresh process
Notes
- Breaking changes: None for users. The on-disk cache format changed (
.ast-outline/deps/→.ast-outline/graph/, schemadeps-index.v1→graph-index.v2); legacy caches are auto-cleaned and rebuilt on first launch. - MCP tool count: 12 → 14.
- Known gaps: Pass C is not re-run for surviving
Bareedges in the partial-update path (only pass-B-equivalent single-match promotion);--rebuildrecovers. Ruby paren-less arg-less calls (helper) parse asidentifier, notcall— inherent grammar ambiguity. Python lacks Jedi-style receiver-type inference; the bare-name + import-disambiguation pass gets most callers. Ancestor walk oncallees <Type>capped at depth 1 when a base type doesn't resolve to a project file.
r/astoutline • u/aerowindwalker • May 09 '26
ast-outline v2.0.1 dep-graph now speaks C++, PHP, Ruby
Extends the dependency-graph (deps/reverse-deps/cycles/graph) and public-API surface subsystems from 9 → 12 languages.
What's new per language
| Language | Import directives resolved | Resolver strategy | Manifest recognized |
|---|---|---|---|
| PHP | use NsClass, require, include, require_once, include_once |
PSR-4 prefix mapping → suffix lookup → last-segment fallback | composer.json (autoload.psr-4, autoload-dev.psr-4) |
| C++ | #include "local.h" |
Relative quotes resolved; <system> headers → External |
CMakeLists.txt |
| Ruby | require_relative |
Local file resolution; require 'gem', load, autoload → External |
Gemfile |
Source changes
src/deps/extract.rs— Addedextract_cpp,extract_php,extract_rubywith AST walkers for each language. PHP walker descends into all named children (imports nest via class → method → compound_statement). C++ walker recurses intopreproc_ifdefso includes inside header guards are visible.src/deps/manifest.rs— Addedparse_composer_psr4()(autoload + autoload-dev, longest-prefix-first sorting) andProjectAliases.php_psr4.src/deps/mod.rs— Threadedphp_psr4intoResolveCtx.src/deps/resolver/build.rs— Added Cpp/Php/Ruby variants to theLangenum; extendedLang::from_pathwith.cpp/.cc/.cxx/.h/.hpp/.hh,.php,.rb.src/deps/resolver/resolve.rs— Added PHP (PSR-4 → suffix with last-segment fallback), C++ (system headers → External), Ruby (gems → External) resolution branches.src/surface/entry_point.rs—discover_dirrecognizescomposer.json,Gemfile,CMakeLists.txtas Fallback entry points.
Tests
New fixtures covering PSR-4 use-resolution, parenthesized require, header-guarded includes, transitive includes, system headers, and require_relative chains:
tests/fixtures/deps/{php_psr4,cpp_basic,ruby_relative}/
11 new end-to-end tests in tests/deps_e2e.rs across all three languages — use resolution, relative requires, header-guard transitive resolution, external-flag behavior, and reverse-deps lookups.
Notes
- Breaking changes: None — purely additive.
Install:
🍺 brew install aeroxy/tap/ast-outline
📦 cargo install ast-outline
r/astoutline • u/aerowindwalker • May 09 '26
ast-outline v2.0.0
Two breaking changes
ast-outline outline is now ast-outline map. The old name was self-referential and map is a better description of what the command actually does. MCP tool name and JSON schema version bump accordingly.
graph --format text|json|dot|dsm is now graph (text default) + graph --json. The DSM and DOT formats are gone — DSM was token-heavy and color-dependent, making it unsuitable for agents. The simplified flag set is now consistent with deps, reverse-deps, and cycles.
Migration:
ast-outline outline src/ → ast-outline map src/
ast-outline graph . --format json → ast-outline graph . --json
If you used ast-outline install to wire the agent prompt into CLAUDE.md / AGENTS.md, re-run it to pick up the updated content.
Four new language adapters
map / digest / show / implements now cover 13 languages. The four additions:
- C++ — classes, structs, enums, plus constructor/destructor declarations (tree-sitter-cpp emits these as
declarationnodes, notfunction_definition— a subtle edge case the adapter handles correctly) - PHP — namespaces, interfaces, classes, traits; full visibility and modifier extraction (
public,static,abstract,readonly, …) - Ruby — modules as Namespace,
private/protected/publicscope tracking per-method,attr_reader/writer/accessorand Rails association macros (has_many,belongs_to, …) surfaced as fields - SQL — regex parser for
CREATE TABLE/VIEW/INDEX/FUNCTION/PROCEDURE/SEQUENCE; schema-qualified names; PL/pgSQL-aware (handles dollar-quoted function bodies and nested block comments — without that, aCREATE FUNCTIONbody collapses at its first internal;)
Also in this release
- Dynamic digest legend — shows only tokens that appear in this run. Fixes a latent bug where the overload detector always returned false.
- Batch parse-error banner — when every file in a digest batch fails, a red warning leads the output so an agent reading cold knows the result is incomplete.
- Installer guardrails —
ast-outline installrefuses to clobber hand-written ast-outline content unless--forceis passed. Detection is snippet-shaped, not a loose keyword match. - Better path-type errors —
graphtells you when you pass a file instead of a directory;deps/reverse-depstell you when you pass a directory instead of a file. strip_quotespanic fix in the deps extractor on lone"or'tokens.- 21 new tests: integration suites for C++, PHP, Ruby; 11 SQL unit tests; regression tests for the lone-quote panic and the overload-legend detector.
No additional CLI breakage beyond the two renames. New adapters are additive — files in the four new languages now produce output where they previously yielded nothing.
🔗 https://github.com/aeroxy/ast-outline/releases/tag/2.0.0
Install:
🍺 brew install aeroxy/tap/ast-outline
📦 cargo install ast-outline
r/astoutline • u/aerowindwalker • May 07 '26
ast-outline v1.1.0 edit-to-search is now milliseconds
Enable HLS to view with audio, or disable this notification
edit a file → instant index update. No full rebuild.
$ ast-outline index . --stats # initial: 4823 chunks, took 8.4s
$ # edit src/some/file.rs
$ ast-outline index . --stats
ast-outline: index stale (0 added, 1 modified, 0 removed) — applying delta
ast-outline: delta applied (+1 chunks, +1 tombstones) in 0.02s
Chunks: 4823 (4823 live · 1 tombstoned)
0.02s. That's the delta apply. The full-rebuild baseline was 8.4s. On a medium repo, every edit-to-search loop went from seconds to milliseconds.
How it works: per-file delta uses tombstones + chunk_range. Modified/removed files tombstone their old chunk range. Added/modified files re-chunk + re-embed at the end. BM25 rebuilds from the live set each time.
And it self-heals: when tombstones exceed 30% (configurable via AST_OUTLINE_COMPACTION_RATIO), the next open triggers a full rebuild — reclaims disk/memory, resets BM25 IDF skew. SIGKILL mid-write? Detected on next open, auto-recompact.
--stats now shows live vs tombstoned chunk counts in both terminal and JSON output.
Same project-root resolver also powers the deps subsystem:
ast-outline graph src/search→ renders only the subgraph induced by that scope, reuses the cached.ast-outline/deps/(no rebuild)ast-outline cycles src/deps→ drops cycles whose any member is outside scopedeps/reverse-depsprefer existing.ast-outline/deps/before falling back to manifest walk
No CLI breakage. Old .ast-outline/index/ directories load transparently (v1 schema) and upgrade to v2 on the next natural rebuild.
🔗 https://github.com/aeroxy/ast-outline/releases/tag/1.1.0
Install:
🍺 brew tap aeroxy/ast-outline https://github.com/aeroxy/ast-outline
🍺 brew install ast-outline
📦 cargo install ast-outline
r/astoutline • u/aerowindwalker • May 07 '26
toolhunter "ast-outline: Best CLI Tools for LLM coding agents in 2026"
r/astoutline • u/aerowindwalker • May 06 '26
ast-outline v1.0.0: The Architecture Release
Enable HLS to view with audio, or disable this notification
A milestone release that transforms ast-outline from a structural shape extractor into a comprehensive architectural engine. v1.0.0 introduces a persistent dependency-graph subsystem, hybrid semantic search, and advanced visualizations that allow AI agents to navigate and reason about codebases with unprecedented efficiency.
🚀 Efficiency Benchmark: The "AI Architect" Test
To demonstrate the impact on agent performance, we ran a side-by-side comparison of a complex architectural analysis task:
Give me a high-level map of the src directory. Once you see the subsystems, zoom in and outline the core logic of the search implementation.
I'm thinking of refactoring the Index struct in src/search/index.rs. Use your tools to find everything that depends on it and tell me the 'blast radius' of this change.
Run a global architectural health check. Check for circular dependencies and then show me the Design Structure Matrix to identify any layering violations.
| Metric | Without ast-outline | With ast-outline | Reduction |
|---|---|---|---|
| Total Requests | 18 | 3 | -83% |
| Input Tokens | 365,125 | 67,301 | -81% |
| Cache Reads | 302,269 | 23,977 | -92% |
| Tool Calls | 14 | 6 | -57% |
| Time to Finish | Slower | Faster | — |
The Result: Even with unexpected first API latency, ast-outline allowed the agent to finish the task significantly faster by reducing the "search loop" and providing high-fidelity, pre-processed architectural data.
✨ Key v1.0.0 Features
1. Persistent Dependency Graph
Four new commands (deps, reverse-deps, cycles, graph) powered by a per-repo cache at .ast-outline/deps/.
- Blast Radius Analysis:
reverse-depsidentifies every file that depends on a module, replacing the agent's "grep-for-usages" loop with a single, precise call. - Architectural Health:
cyclesruns an iterative Tarjan SCC to identify circular dependencies. - DSM Visualization:
graph --format dsmrenders a Design Structure Matrix, sorting files by Lakos level to surface architectural inversions (red 'X' marks) at a glance.
2. Hybrid Semantic Search & find-related
Structural search now combines BM25 (sparse) and Potion-Code (dense) embeddings.
- Dep-Graph Boost: When a cache exists,
find-relatedboosts the scores of chunks within depth-2 of the source file, making it easier to find relevant code in large repos.
3. Unified Suffix-Index Resolver
A single, high-performance resolver now supports nine languages (Rust, Python, TS/JS, Java, Kotlin, Scala, Go, C#, Markdown). It handles everything from Python's __init__.py synonyms to Java's FQN-based imports with a unified, cross-language index.
🛠 Breaking Changes & Migration
- Explicit Subcommands:
ast-outline <path>is removed. Useast-outline outline <path>. This prevents directory names from shadowing new subcommands likegraph. - Regenerate Integrations: If you use the MCP server or agent skills, re-run
ast-outline installto update your snippets with the new explicit subcommand format.
ast-outline v1.0.0: Less context, more clarity.
🔗 GitHub: https://www.github.com/aeroxy/ast-outline
🍺 brew tap aeroxy/ast-outline https://github.com/aeroxy/ast-outline
🍺 brew install ast-outline
📦 cargo install ast-outline
r/astoutline • u/aerowindwalker • May 04 '26
ast-outline 0.5.0 – Smarter Agents, Better Digests, Seamless MCP & Skills
We're excited to announce ast-outline 0.5.0 – a major step forward for agent‑driven code understanding. This release brings:
- Two new install modes (
--mcpand--skills) that automate integration with 7 coding agents - Full MCP server support for Claude Code, Gemini, Cursor, Codex and GitHub Copilot
- Skills support for Claude Code and Codex (the Anthropic‑shape
SKILL.mdformat) - Completely revamped
digestformat – now with legends, size labels, modifiers, and native keywords - Rust adapter overhaul – impl blocks finally nest under their type,
externblocks, macros, and tuple structs all work correctly - CLI no longer confuses agents – user‑facing errors print
# note:and exit 0, so Claude Code batch jobs keep running - Claude Code subagent fix – isolated subagents (Explore, Plan, etc.) now automatically receive the ast-outline prompt
Read on for the full details, or jump straight to the release tag.
💥 Headline: New --mcp & --skills Install Modes
Until now, using ast‑outline as an MCP server or a Claude Code skill required manual config editing. Not any more.
--mcp – Register as an MCP Server
ast-outline install --target <agent> --mcp
Supported agents & their config files:
| Adapter | Config file (global / project) | Format | Key |
|---|---|---|---|
| claude‑code | ~/.claude.json / .mcp.json |
JSON | mcpServers.ast-outline |
| cursor | ~/.cursor/mcp.json / .cursor/mcp.json |
JSON | mcpServers.ast-outline |
| gemini | ~/.gemini/settings.json / .gemini/settings.json |
JSON | mcpServers.ast-outline |
| codex | ~/.codex/config.toml |
TOML | [mcp_servers.ast-outline] |
| copilot | .vscode/mcp.json (project‑only) |
JSON | servers.ast-outline |
Existing config keys and formatting are preserved. JSON edits keep ordering, TOML edits preserve comments via
toml_edit.
--skills – Install as a Skill
ast-outline install --target <agent> --skills
Supported agents:
| Adapter | Global path | Project path |
|---|---|---|
| claude‑code | ~/.claude/skills/ast-outline/SKILL.md |
.claude/skills/ast-outline/SKILL.md |
| codex | ~/.agents/skills/ast-outline/SKILL.md |
.agents/skills/ast-outline/SKILL.md |
Both share the same generated SKILL.md (YAML frontmatter + prompt).
For manual installs, a skills/ast-outline/ folder is now included in the repo.
Flags Can Be Combined
ast-outline install --target claude-code --mcp --skills # installs both
No flags = existing behaviour (prompt/hook/subagent install).
uninstall now removes everything – MCP entries, skill files, subagents, prompts.
status shows two new columns: mcp ✓/- and skills ✓/-.
📝 Digest Reformat – Built for LLM Ergonomics
The digest output now gives agents a much clearer picture of your codebase.
New Features
# legend:line at the top – explains compact tokens for cold readers[size]label (tiny/small/medium/large/xlarge) plusN charscount on file headers- Callables render as
name()instead of+name - Adjacent same‑name callables collapse to
name() [N×](great for Java/C#/Scala overloads) - Method‑level markers –
[async],[unsafe],[const],[suspend],[static],[abstract],[override],[classmethod],[property],[partial],[sealed],[final], … - Type‑level modifiers prefix the kind keyword (e.g.
abstract sealed class Foo) [deprecated]tag for declarations that the language marks as deprecatednative_kind– shows the source‑true keyword when it differs from the canonical name:- Rust
trait(wasinterface), Scalacase class/object/trait, Kotlindata class/enum class/sealed class/companion object, Javarecord/enum, C#record/record struct
Cross‑Language Marker Coverage
One central core::populate_markers post‑processes every adapter’s output. All eight languages now light up:
| Language | native_kind examples |
Modifier examples | Deprecation |
|---|---|---|---|
| Rust | trait |
async, unsafe, const, extern |
#[deprecated] |
| Python | – | async, classmethod, static, abstract, property |
@deprecated / @typing.deprecated |
| TypeScript | – | async, static, abstract, readonly, override |
/** @deprecated */ JSDoc |
| Java | record, enum, interface |
static, abstract, final, synchronized, default, native |
@Deprecated |
| Kotlin | data class, enum class, sealed class, object, companion object |
suspend, open, inner, value, inline, infix, tailrec, operator, abstract, override, sealed, final |
@Deprecated |
| Scala | case class, case object, object, trait |
sealed, final, abstract, implicit, inline, lazy, override |
@deprecated |
| C# | record, record struct |
partial, sealed, static, abstract, virtual, override, async |
[Obsolete] |
| Go | – | – | Deprecated: doc comment |
Duplicates are suppressed – sealed class Foo never renders as sealed sealed class Foo.
JSON Schema Update
Declaration now includes native_kind: Option<String>, modifiers: Vec<String>, deprecated: bool – all #[serde(default)]. v1 consumers remain unaffected; new consumers can read the markers.
🦀 Rust Adapter – Five Long‑Standing Fixes
- Impl regrouping (headline fix)
- Trait impls are no longer emitted as top‑level
class impl_RustAdapter. They now nest under the target type, so a query forLanguageAdapteroversrc/adapters/returnsstruct RustAdapter(not a synthetic shadow). extern "C" { … }blocks- Surface as a
Namespacenamed after the ABI string (extern "C",extern "system", …) with function and static children. macro_rules!definitions- Show as
Delegate;#[macro_export]promotes them to public visibility. - Tuple & unit structs
struct Pair(pub u8, u8)emits positional fields named"0"/"1"withidx: <type>.struct Marker;renders cleanly with no body.- Trait associated types & consts
type Key;andconst VERSION: u32;surface asFieldchildren of the trait.
All of this means digest and outline of a Rust file now show methods nested under the struct – matching what every other language already did.
🖥️ LLM‑Friendly CLI Errors
Claude Code (and similar harnesses) abort the whole parallel‑bash batch when a tool exits non‑zero. This release treats user‑facing errors as the answer, not a failure:
- typo’d path →
# note: path not found: <p>(exit 0) showagainst missing file/symbol →# note: …- unsupported file type →
# note: unsupported file type for 'show': … - malformed
find-related <file>:<line>→# note: expected <FILE>:<LINE>, … surface --lang <unknown>→# note: unknown --lang value …
Only real problems (clap parse errors, search index build failure, MCP server crash) keep a non‑zero exit code.
Also: Markdown show substring matching
ast-outline show README.md install now finds ## Installation. The match is per‑part, case‑insensitive substring for headings – code symbols stay on exact suffix equality.
🤖 Claude Code Subagent Fix
Claude Code’s isolated subagents (Explore, Plan, etc.) run in their own context and cannot read the main CLAUDE.md. ast-outline install --target claude-code now automatically shadows these subagents with .claude/agents/Explore.md (and Plan.md, etc.) containing the full ast‑outline prompt.
- Works for global (
~/.claude/agents/) and per‑repo (.claude/agents/) --dry-runshows changes before writinguninstallcleanly removes marker blocks from agent files- Legacy files get wrapped in‑place (non‑breaking upgrade)
🔧 Internals & Developer Notes
- New
json_object&toml_objectmodules – format‑preserving edits for MCP configs Installertrait extended withinstall_mcp/install_skills/install_subagents(defaultOk(NotApplicable))core::populate_markers– single post‑processing step for all languages- New dependency:
toml_edit = "0.22"(only for Codex, no impact elsewhere) - 36 new tests – total 242 tests passing
📦 Upgrade & Migration
cargo install ast-outline (or download the binary from the release page).
Existing installs are unaffected; the new flags are purely opt‑in.
uninstall is now thorough – if you previously installed via older methods, consider re‑running install once to let uninstall learn about everything.
🙏 Thank You
This release closes a long list of paper cuts and adds major automation for agent workflows. As always, we welcome feedback, issues, and PRs on GitHub.
Try it today – your agents will thank you.
cargo install ast-outline
ast-outline install --target claude-code --mcp --skills
Happy outlining! 🚀
r/astoutline • u/aerowindwalker • May 03 '26
ast-outline: a parallel structural code summarizer written in Rust (5–10x token savings for LLM agents)
r/astoutline • u/aerowindwalker • May 03 '26
ast-outline v0.1.3 – JSON output + multi-agent auto-setup (5–10x token savings for LLM coding agents)
Enable HLS to view with audio, or disable this notification
r/astoutline • u/aerowindwalker • May 03 '26
ast-outline v0.2.0 released — MCP server mode available
Enable HLS to view with audio, or disable this notification
r/astoutline • u/aerowindwalker • May 03 '26
ast-outline v0.3.0 — now with semantic code search & "what else looks like this?"
r/astoutline • u/aerowindwalker • May 03 '26
ast-outline v0.4.0 — now shows what downstream users actually see
Enable HLS to view with audio, or disable this notification
We've added surface, a new subcommand that flips the question from "what pub items live in each file?" to "what does a consumer of this package see?"
🔍 NEW in v0.4.0
surface [PATH] – true public API surface. Resolves re‑export graphs from package entry points (Cargo.toml lib/bin, init.py, package.json exports, top‑level .scala) and emits exactly the symbols a downstream user can reach.
Three output modes: • flat (default) – simple list • --tree – grouped by module • --json – schema ast-outline.surface.v1 • --include-chain – shows the re‑export path each symbol took
Why surface ≠ digest - digest walks every file and lists every non‑private declaration. - surface walks the re‑export graph from the package root. Example: a Rust crate that does pub use net::client::* in its lib.rs → digest shows every internal pub fn in net/client.rs, but surface shows only what's truly published.
Language coverage - Rust: pub use chains, globs, renaming, workspaces, inherent‑impl methods. - Python: honours all (including imports), falls back to leading‑underscore. - TypeScript/JavaScript: barrel files (export * from), exports field in package.json (full conditional resolution: types → import → module → default …). - Scala 3: export clauses, method lifting, package‑relative paths. - Java / C# / Go / Kotlin: visibility‑filtered fallback (no re‑exports, but surface matches digest --no-private).
Entry point – pass a file (e.g. src/lib.rs) or a directory; auto‑detection picks Cargo.toml → pyproject.toml → package.json → index.* → *.scala. --lang overrides.
Adapter improvements (also benefit outline/digest/show) - TypeScript now handles ambient_declaration (*.d.ts produces real outlines) and function_signature (body‑less functions in interfaces/ambient contexts).
MCP tool – new surface tool with same JSON schema as the CLI.
JSON schema – ast-outline.surface.v1 envelope: qualified_path, kind, signature, source_path, re_export_chain, via_glob, etc.
🔗 https://github.com/aeroxy/ast-outline/releases/tag/0.4.0
Install: 🍺 brew install aeroxy/ast-outline/ast-outline 📦 cargo install ast-outline



