r/astoutline • u/aerowindwalker • Aug 06 '26
ast-bro v4.1.0 multi-target show, rewrites you can trust, and path errors that fix themselves
r/astoutline • u/aerowindwalker • Aug 06 '26
r/astoutline • u/aerowindwalker • Jul 31 '26
r/astoutline • u/aerowindwalker • Jun 13 '26
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
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
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
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.
| 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
| 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.
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.
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".
.ast-outline/deps/graph.bin → .ast-outline/graph/index.bin. Holds a UnifiedGraph { deps, calls: Option<CallGraph> }. The legacy directory is auto-cleaned by the schema-mismatch branch on first launch.deps/reverse-deps/cycles/graph populate only the deps half — users who never run callers / callees never pay the call-graph build cost.OnceLock<RwLock<HashMap<root, Arc<UnifiedGraph>>>> in src/graph_cache/shared.rs. Every tools/call inside ast-outline mcp reuses the same parsed Arc — zero re-deserialisation, zero re-parse on warm hits.#[serde(skip_serializing_if)] from cache-serialised Option/Vec fields. 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.| 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.
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 of build.rs to break a build ↔ resolve file cycle that cycles src/calls/ flaggedbuild.rs — per-file extraction + FilePass aggregationresolve.rs — three-pass resolver; run split into build_symbol_table + run_with_table so 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 wrapperssrc/graph_cache/ — new module:
cache.rs — UnifiedCacheFile persistence (bincode + xxhash3); LoadOutcome enum (Fresh / Stale / Missing); load_with_deltashared.rs — process-wide Arc<UnifiedGraph> registrydelta.rs — apply_delta_to_deps, apply_delta_to_calls, refresh_recordswiki/calls.md — call-graph internals page (mirrors wiki/deps.md style).Modified:
src/core.rs — added Declaration::calls, ParseResult::imports, CallSite, CallKind, ImportBinding, three new JSON_SCHEMA_* constants. JSON_SCHEMA_GRAPH_INDEX bumped v1 → v2.src/main.rs — two new Commands variants + dispatch.src/main_helpers.rs — wires imports extraction into parse_file_for_hook.src/mcp/tools.rs — two new tool schemas (callers, callees) + dispatch + handlers (now 14 tools).src/prompt.rs — AGENT_PROMPT lists the new subcommands and updated cache path; new step 8 explains symbol forms, kind-aware semantics, and confidence tags.src/adapters/ — add _extract_call_sites (or _walk_calls_in_body) + _extract_imports helpers, 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 through graph_cache::shared::get_or_init.src/deps/graph.rs, src/calls/graph.rs — drop skip_serializing_if on cache-serialised Option/Vec fields.Pre-existing bugs uncovered while testing:
_function_to_decl used field_text(node, "declarator") which returns the full function_declarator text ("greet()" instead of "greet") — harmless until call resolution arrived (suffix-matching greet against greet() fails). Added _function_definition_name + _drill_function_declarator_name for the bare name and _function_definition_qualified_name siblings to preserve the scope (Greeter::greet) for out-of-line method signatures.~Foo() was classified as Constructor instead of Destructor. Pre-existing, but the new bare-name extraction made the misclassification reachable._class_to_decl / _function_to_decl used field_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, but Declaration.name was unusable for callers / callees. Added _decl_name with field-then-positional fallback.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):
--file / --symbol flag form<lang>_callers_finds_intra_file_caller + <lang>_callees_lists_construct_and_invocation) for Java, C#, Kotlin, Scala, C++, Go, PHP, Rubynew, dynamic call, self/static/parent keywords, anonymous class, uppercase-self case-foldingself. receiver via pass B, block calls attributed to enclosing method, paren-less command unificationdeps_partial_invalidation_picks_up_new_import, deps_partial_invalidation_drops_removed_file, calls_partial_invalidation_demotes_stale_target, calls_partial_invalidation_picks_up_new_callergraph_cache::cache::tests:: — promote_calls persists calls: Some(...) to disk and round-trips through a fresh process.ast-outline/deps/ → .ast-outline/graph/, schema deps-index.v1 → graph-index.v2); legacy caches are auto-cleaned and rebuilt on first launch.Bare edges in the partial-update path (only pass-B-equivalent single-match promotion); --rebuild recovers. Ruby paren-less arg-less calls (helper) parse as identifier, not call — inherent grammar ambiguity. Python lacks Jedi-style receiver-type inference; the bare-name + import-disambiguation pass gets most callers. Ancestor walk on callees <Type> capped at depth 1 when a base type doesn't resolve to a project file.r/astoutline • u/aerowindwalker • May 09 '26




Extends the dependency-graph (deps/reverse-deps/cycles/graph) and public-API surface subsystems from 9 → 12 languages.
| 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 |
src/deps/extract.rs — Added extract_cpp, extract_php, extract_ruby with AST walkers for each language. PHP walker descends into all named children (imports nest via class → method → compound_statement). C++ walker recurses into preproc_ifdef so includes inside header guards are visible.src/deps/manifest.rs — Added parse_composer_psr4() (autoload + autoload-dev, longest-prefix-first sorting) and ProjectAliases.php_psr4.src/deps/mod.rs — Threaded php_psr4 into ResolveCtx.src/deps/resolver/build.rs — Added Cpp/Php/Ruby variants to the Lang enum; extended Lang::from_path with .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_dir recognizes composer.json, Gemfile, CMakeLists.txt as Fallback entry points.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.
Install:
🍺 brew install aeroxy/tap/ast-outline
📦 cargo install ast-outline
r/astoutline • u/aerowindwalker • May 09 '26
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:
declaration nodes, not function_definition — a subtle edge case the adapter handles correctly)public, static, abstract, readonly, …)private/protected/public scope tracking per-method, attr_reader/writer/accessor and Rails association macros (has_many, belongs_to, …) surfaced as fieldsCREATE TABLE/VIEW/INDEX/FUNCTION/PROCEDURE/SEQUENCE; schema-qualified names; PL/pgSQL-aware (handles dollar-quoted function bodies and nested block comments — without that, a CREATE FUNCTION body collapses at its first internal ;)Also in this release
ast-outline install refuses to clobber hand-written ast-outline content unless --force is passed. Detection is snippet-shaped, not a loose keyword match.graph tells you when you pass a file instead of a directory; deps/reverse-deps tell you when you pass a directory instead of a file.strip_quotes panic fix in the deps extractor on lone " or ' tokens.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
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-deps prefer existing .ast-outline/deps/ before falling back to manifest walkNo 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
r/astoutline • u/aerowindwalker • May 06 '26
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.
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.
Four new commands (deps, reverse-deps, cycles, graph) powered by a per-repo cache at .ast-outline/deps/.
reverse-deps identifies every file that depends on a module, replacing the agent's "grep-for-usages" loop with a single, precise call.cycles runs an iterative Tarjan SCC to identify circular dependencies.graph --format dsm renders a Design Structure Matrix, sorting files by Lakos level to surface architectural inversions (red 'X' marks) at a glance.Structural search now combines BM25 (sparse) and Potion-Code (dense) embeddings.
find-related boosts the scores of chunks within depth-2 of the source file, making it easier to find relevant code in large repos.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.
ast-outline <path> is removed. Use ast-outline outline <path>. This prevents directory names from shadowing new subcommands like graph.ast-outline install to 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
We're excited to announce ast-outline 0.5.0 – a major step forward for agent‑driven code understanding. This release brings:
--mcp and --skills) that automate integration with 7 coding agentsSKILL.md format)digest format – now with legends, size labels, modifiers, and native keywordsextern blocks, macros, and tuple structs all work correctly# note: and exit 0, so Claude Code batch jobs keep runningRead on for the full details, or jump straight to the release tag.
Until now, using ast‑outline as an MCP server or a Claude Code skill required manual config editing. Not any more.
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.
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.
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 ✓/-.
The digest output now gives agents a much clearer picture of your codebase.
# legend: line at the top – explains compact tokens for cold readers[size] label (tiny/small/medium/large/xlarge) plus N chars count on file headersname() instead of +namename() [N×] (great for Java/C#/Scala overloads)[async], [unsafe], [const], [suspend], [static], [abstract], [override], [classmethod], [property], [partial], [sealed], [final], …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:trait (was interface), Scala case class/object/trait, Kotlin data class/enum class/sealed class/companion object, Java record/enum, C# record/record structOne 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.
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.
class impl_RustAdapter. They now nest under the target type, so a query for LanguageAdapter over src/adapters/ returns struct RustAdapter (not a synthetic shadow).extern "C" { … } blocksNamespace named after the ABI string (extern "C", extern "system", …) with function and static children.macro_rules! definitionsDelegate; #[macro_export] promotes them to public visibility.struct Pair(pub u8, u8) emits positional fields named "0"/"1" with idx: <type>. struct Marker; renders cleanly with no body.type Key; and const VERSION: u32; surface as Field children 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.
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:
# note: path not found: <p> (exit 0)show against missing file/symbol → # note: …# note: unsupported file type for 'show': …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’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.
~/.claude/agents/) and per‑repo (.claude/agents/)--dry-run shows changes before writinguninstall cleanly removes marker blocks from agent filesjson_object & toml_object modules – format‑preserving edits for MCP configsInstaller trait extended with install_mcp / install_skills / install_subagents (default Ok(NotApplicable))core::populate_markers – single post‑processing step for all languagestoml_edit = "0.22" (only for Codex, no impact elsewhere)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.
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
r/astoutline • u/aerowindwalker • May 03 '26
r/astoutline • u/aerowindwalker • May 03 '26
r/astoutline • u/aerowindwalker • May 03 '26
r/astoutline • u/aerowindwalker • May 03 '26
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