ast-outline 0.4.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. ast_outline-0.4.3/.gitignore +32 -0
  2. ast_outline-0.4.3/LICENSE +21 -0
  3. ast_outline-0.4.3/PKG-INFO +611 -0
  4. ast_outline-0.4.3/README.md +574 -0
  5. ast_outline-0.4.3/pyproject.toml +96 -0
  6. ast_outline-0.4.3/src/ast_outline/__init__.py +7 -0
  7. ast_outline-0.4.3/src/ast_outline/_prompt.py +58 -0
  8. ast_outline-0.4.3/src/ast_outline/adapters/__init__.py +71 -0
  9. ast_outline-0.4.3/src/ast_outline/adapters/base.py +40 -0
  10. ast_outline-0.4.3/src/ast_outline/adapters/csharp.py +411 -0
  11. ast_outline-0.4.3/src/ast_outline/adapters/go.py +763 -0
  12. ast_outline-0.4.3/src/ast_outline/adapters/java.py +573 -0
  13. ast_outline-0.4.3/src/ast_outline/adapters/kotlin.py +858 -0
  14. ast_outline-0.4.3/src/ast_outline/adapters/markdown.py +257 -0
  15. ast_outline-0.4.3/src/ast_outline/adapters/python.py +276 -0
  16. ast_outline-0.4.3/src/ast_outline/adapters/rust.py +1109 -0
  17. ast_outline-0.4.3/src/ast_outline/adapters/scala.py +975 -0
  18. ast_outline-0.4.3/src/ast_outline/adapters/typescript.py +672 -0
  19. ast_outline-0.4.3/src/ast_outline/adapters/yaml.py +740 -0
  20. ast_outline-0.4.3/src/ast_outline/cli.py +611 -0
  21. ast_outline-0.4.3/src/ast_outline/core.py +1223 -0
  22. ast_outline-0.4.3/tests/conftest.py +59 -0
  23. ast_outline-0.4.3/tests/fixtures/csharp/broken_syntax.cs +18 -0
  24. ast_outline-0.4.3/tests/fixtures/csharp/file_scoped_ns.cs +41 -0
  25. ast_outline-0.4.3/tests/fixtures/csharp/hierarchy.cs +52 -0
  26. ast_outline-0.4.3/tests/fixtures/csharp/nested_and_overloads.cs +50 -0
  27. ast_outline-0.4.3/tests/fixtures/csharp/unity_behaviour.cs +53 -0
  28. ast_outline-0.4.3/tests/fixtures/csharp/visibility_defaults.cs +23 -0
  29. ast_outline-0.4.3/tests/fixtures/go/broken_syntax.go +12 -0
  30. ast_outline-0.4.3/tests/fixtures/go/comments_edge.go +19 -0
  31. ast_outline-0.4.3/tests/fixtures/go/edge_cases.go +106 -0
  32. ast_outline-0.4.3/tests/fixtures/go/enum_iota.go +37 -0
  33. ast_outline-0.4.3/tests/fixtures/go/generics.go +45 -0
  34. ast_outline-0.4.3/tests/fixtures/go/hierarchy.go +49 -0
  35. ast_outline-0.4.3/tests/fixtures/go/multidir/base/animal.go +12 -0
  36. ast_outline-0.4.3/tests/fixtures/go/multidir/felines/cat.go +11 -0
  37. ast_outline-0.4.3/tests/fixtures/go/multidir/mammals/dog.go +17 -0
  38. ast_outline-0.4.3/tests/fixtures/go/multidir/mammals/puppy.go +6 -0
  39. ast_outline-0.4.3/tests/fixtures/go/no_package_methods.go +22 -0
  40. ast_outline-0.4.3/tests/fixtures/go/user_service.go +104 -0
  41. ast_outline-0.4.3/tests/fixtures/java/annotation_type.java +33 -0
  42. ast_outline-0.4.3/tests/fixtures/java/broken_syntax.java +15 -0
  43. ast_outline-0.4.3/tests/fixtures/java/generics_throws.java +35 -0
  44. ast_outline-0.4.3/tests/fixtures/java/hierarchy.java +42 -0
  45. ast_outline-0.4.3/tests/fixtures/java/line_comment.java +4 -0
  46. ast_outline-0.4.3/tests/fixtures/java/multi_var_fields.java +21 -0
  47. ast_outline-0.4.3/tests/fixtures/java/multidir/base/Animal.java +6 -0
  48. ast_outline-0.4.3/tests/fixtures/java/multidir/felines/Cat.java +9 -0
  49. ast_outline-0.4.3/tests/fixtures/java/multidir/mammals/Dog.java +9 -0
  50. ast_outline-0.4.3/tests/fixtures/java/multidir/mammals/Puppy.java +7 -0
  51. ast_outline-0.4.3/tests/fixtures/java/no_package.java +15 -0
  52. ast_outline-0.4.3/tests/fixtures/java/plain_block_comment.java +4 -0
  53. ast_outline-0.4.3/tests/fixtures/java/records_and_sealed.java +70 -0
  54. ast_outline-0.4.3/tests/fixtures/java/repository.java +39 -0
  55. ast_outline-0.4.3/tests/fixtures/java/status_enum.java +38 -0
  56. ast_outline-0.4.3/tests/fixtures/java/user_service.java +63 -0
  57. ast_outline-0.4.3/tests/fixtures/kotlin/annotations_generics.kt +35 -0
  58. ast_outline-0.4.3/tests/fixtures/kotlin/broken_syntax.kt +7 -0
  59. ast_outline-0.4.3/tests/fixtures/kotlin/companion_and_objects.kt +46 -0
  60. ast_outline-0.4.3/tests/fixtures/kotlin/data_and_sealed.kt +40 -0
  61. ast_outline-0.4.3/tests/fixtures/kotlin/extensions_and_toplevel.kt +30 -0
  62. ast_outline-0.4.3/tests/fixtures/kotlin/hierarchy.kt +26 -0
  63. ast_outline-0.4.3/tests/fixtures/kotlin/line_comment.kt +5 -0
  64. ast_outline-0.4.3/tests/fixtures/kotlin/multidir/base/Animal.kt +5 -0
  65. ast_outline-0.4.3/tests/fixtures/kotlin/multidir/felines/Cat.kt +7 -0
  66. ast_outline-0.4.3/tests/fixtures/kotlin/multidir/mammals/Dog.kt +7 -0
  67. ast_outline-0.4.3/tests/fixtures/kotlin/multidir/mammals/Puppy.kt +3 -0
  68. ast_outline-0.4.3/tests/fixtures/kotlin/no_package.kt +11 -0
  69. ast_outline-0.4.3/tests/fixtures/kotlin/plain_block_comment.kt +4 -0
  70. ast_outline-0.4.3/tests/fixtures/kotlin/properties.kt +31 -0
  71. ast_outline-0.4.3/tests/fixtures/kotlin/secondary_ctor.kt +17 -0
  72. ast_outline-0.4.3/tests/fixtures/kotlin/user_service.kt +58 -0
  73. ast_outline-0.4.3/tests/fixtures/markdown/article.md +33 -0
  74. ast_outline-0.4.3/tests/fixtures/markdown/decorated_headings.md +20 -0
  75. ast_outline-0.4.3/tests/fixtures/markdown/empty.md +3 -0
  76. ast_outline-0.4.3/tests/fixtures/markdown/readme_style.md +51 -0
  77. ast_outline-0.4.3/tests/fixtures/markdown/setext_and_codes.md +26 -0
  78. ast_outline-0.4.3/tests/fixtures/python/async_service.py +53 -0
  79. ast_outline-0.4.3/tests/fixtures/python/broken_syntax.py +16 -0
  80. ast_outline-0.4.3/tests/fixtures/python/decorators_edge.py +44 -0
  81. ast_outline-0.4.3/tests/fixtures/python/domain_model.py +83 -0
  82. ast_outline-0.4.3/tests/fixtures/python/hierarchy.py +55 -0
  83. ast_outline-0.4.3/tests/fixtures/rust/broken_syntax.rs +17 -0
  84. ast_outline-0.4.3/tests/fixtures/rust/comments_edge.rs +40 -0
  85. ast_outline-0.4.3/tests/fixtures/rust/cross_file_impl.rs +32 -0
  86. ast_outline-0.4.3/tests/fixtures/rust/edge_cases.rs +28 -0
  87. ast_outline-0.4.3/tests/fixtures/rust/enum_advanced.rs +32 -0
  88. ast_outline-0.4.3/tests/fixtures/rust/extern_block.rs +22 -0
  89. ast_outline-0.4.3/tests/fixtures/rust/generics.rs +58 -0
  90. ast_outline-0.4.3/tests/fixtures/rust/hierarchy.rs +58 -0
  91. ast_outline-0.4.3/tests/fixtures/rust/modules.rs +29 -0
  92. ast_outline-0.4.3/tests/fixtures/rust/unions_and_macros.rs +32 -0
  93. ast_outline-0.4.3/tests/fixtures/rust/user_service.rs +71 -0
  94. ast_outline-0.4.3/tests/fixtures/rust/visibility_matrix.rs +19 -0
  95. ast_outline-0.4.3/tests/fixtures/scala/braced_package.scala +11 -0
  96. ast_outline-0.4.3/tests/fixtures/scala/broken_syntax.scala +8 -0
  97. ast_outline-0.4.3/tests/fixtures/scala/companion_and_objects.scala +39 -0
  98. ast_outline-0.4.3/tests/fixtures/scala/data_and_sealed.scala +32 -0
  99. ast_outline-0.4.3/tests/fixtures/scala/extensions_and_toplevel.scala +21 -0
  100. ast_outline-0.4.3/tests/fixtures/scala/hierarchy.scala +27 -0
  101. ast_outline-0.4.3/tests/fixtures/scala/line_comment.scala +5 -0
  102. ast_outline-0.4.3/tests/fixtures/scala/multidir/base/Animal.scala +5 -0
  103. ast_outline-0.4.3/tests/fixtures/scala/multidir/felines/Cat.scala +7 -0
  104. ast_outline-0.4.3/tests/fixtures/scala/multidir/mammals/Dog.scala +7 -0
  105. ast_outline-0.4.3/tests/fixtures/scala/multidir/mammals/Puppy.scala +3 -0
  106. ast_outline-0.4.3/tests/fixtures/scala/no_package.scala +11 -0
  107. ast_outline-0.4.3/tests/fixtures/scala/package_object.scala +11 -0
  108. ast_outline-0.4.3/tests/fixtures/scala/plain_block_comment.scala +4 -0
  109. ast_outline-0.4.3/tests/fixtures/scala/scala3_features.scala +29 -0
  110. ast_outline-0.4.3/tests/fixtures/scala/user_service.scala +56 -0
  111. ast_outline-0.4.3/tests/fixtures/typescript/broken_syntax.ts +16 -0
  112. ast_outline-0.4.3/tests/fixtures/typescript/decorators.ts +29 -0
  113. ast_outline-0.4.3/tests/fixtures/typescript/hierarchy.ts +40 -0
  114. ast_outline-0.4.3/tests/fixtures/typescript/plain_module.js +25 -0
  115. ast_outline-0.4.3/tests/fixtures/typescript/react_page.tsx +40 -0
  116. ast_outline-0.4.3/tests/fixtures/typescript/storage_service.ts +59 -0
  117. ast_outline-0.4.3/tests/fixtures/typescript/types.ts +34 -0
  118. ast_outline-0.4.3/tests/fixtures/typescript/visibility.ts +18 -0
  119. ast_outline-0.4.3/tests/fixtures/yaml/anchors_aliases.yaml +12 -0
  120. ast_outline-0.4.3/tests/fixtures/yaml/app_config.yaml +26 -0
  121. ast_outline-0.4.3/tests/fixtures/yaml/block_scalars.yaml +15 -0
  122. ast_outline-0.4.3/tests/fixtures/yaml/broken_syntax.yaml +11 -0
  123. ast_outline-0.4.3/tests/fixtures/yaml/dotted_keys.yaml +21 -0
  124. ast_outline-0.4.3/tests/fixtures/yaml/github_workflow.yaml +20 -0
  125. ast_outline-0.4.3/tests/fixtures/yaml/helm_templated.yaml +22 -0
  126. ast_outline-0.4.3/tests/fixtures/yaml/k8s_deployment.yaml +36 -0
  127. ast_outline-0.4.3/tests/fixtures/yaml/k8s_multi_resources.yaml +38 -0
  128. ast_outline-0.4.3/tests/fixtures/yaml/openapi_mini.yaml +57 -0
  129. ast_outline-0.4.3/tests/fixtures/yaml/seq_id_fallback.yaml +30 -0
  130. ast_outline-0.4.3/tests/sample.cs +50 -0
  131. ast_outline-0.4.3/tests/sample.py +59 -0
  132. ast_outline-0.4.3/tests/unit/__init__.py +0 -0
  133. ast_outline-0.4.3/tests/unit/test_cli.py +348 -0
  134. ast_outline-0.4.3/tests/unit/test_core_renderers.py +185 -0
  135. ast_outline-0.4.3/tests/unit/test_core_search.py +716 -0
  136. ast_outline-0.4.3/tests/unit/test_csharp_adapter.py +289 -0
  137. ast_outline-0.4.3/tests/unit/test_digest_format.py +1208 -0
  138. ast_outline-0.4.3/tests/unit/test_go_adapter.py +709 -0
  139. ast_outline-0.4.3/tests/unit/test_header_enrichment.py +644 -0
  140. ast_outline-0.4.3/tests/unit/test_java_adapter.py +658 -0
  141. ast_outline-0.4.3/tests/unit/test_kotlin_adapter.py +677 -0
  142. ast_outline-0.4.3/tests/unit/test_markdown_adapter.py +214 -0
  143. ast_outline-0.4.3/tests/unit/test_prompt_command.py +205 -0
  144. ast_outline-0.4.3/tests/unit/test_python_adapter.py +256 -0
  145. ast_outline-0.4.3/tests/unit/test_rust_adapter.py +1118 -0
  146. ast_outline-0.4.3/tests/unit/test_scala_adapter.py +587 -0
  147. ast_outline-0.4.3/tests/unit/test_typescript_adapter.py +347 -0
  148. ast_outline-0.4.3/tests/unit/test_yaml_adapter.py +519 -0
@@ -0,0 +1,32 @@
1
+ # Virtual environments
2
+ .venv/
3
+ venv/
4
+ env/
5
+
6
+ # Python build / bytecode
7
+ __pycache__/
8
+ *.py[cod]
9
+ *$py.class
10
+ *.egg-info/
11
+ dist/
12
+ build/
13
+ .eggs/
14
+
15
+ # Tooling caches
16
+ .pytest_cache/
17
+ .mypy_cache/
18
+ .ruff_cache/
19
+ .tox/
20
+ .coverage
21
+ htmlcov/
22
+
23
+ # IDE / OS
24
+ .DS_Store
25
+ .idea/
26
+ .vscode/
27
+ *.swp
28
+ *.swo
29
+
30
+ # Distribution
31
+ *.whl
32
+ *.tar.gz
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ast-outline contributors (formerly code-outline)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,611 @@
1
+ Metadata-Version: 2.4
2
+ Name: ast-outline
3
+ Version: 0.4.3
4
+ Summary: AST-based structural outline for source files (C#, Python, TypeScript/JavaScript, Java, Kotlin, Scala, Go, Rust, Markdown, YAML) — tree-sitter-powered, LLM-agent-first. Complement to ast-grep: ast-grep searches, ast-outline overviews.
5
+ Project-URL: Homepage, https://github.com/dim-s/ast-outline
6
+ Project-URL: Issues, https://github.com/dim-s/ast-outline/issues
7
+ Project-URL: Repository, https://github.com/dim-s/ast-outline
8
+ Author: ast-outline contributors
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: ast,ast-grep,code-navigation,coding-agent,csharp,go,golang,java,javascript,kotlin,kubernetes,llm,markdown,openapi,outline,python,rust,scala,tree-sitter,typescript,yaml
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: Utilities
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: tree-sitter-c-sharp>=0.23
24
+ Requires-Dist: tree-sitter-go>=0.23
25
+ Requires-Dist: tree-sitter-java>=0.23
26
+ Requires-Dist: tree-sitter-kotlin>=1.1
27
+ Requires-Dist: tree-sitter-markdown>=0.3
28
+ Requires-Dist: tree-sitter-python>=0.23
29
+ Requires-Dist: tree-sitter-rust>=0.23
30
+ Requires-Dist: tree-sitter-scala>=0.24
31
+ Requires-Dist: tree-sitter-typescript>=0.23
32
+ Requires-Dist: tree-sitter-yaml>=0.6
33
+ Requires-Dist: tree-sitter>=0.23
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=8; extra == 'dev'
36
+ Description-Content-Type: text/markdown
37
+
38
+ # ast-outline
39
+
40
+ **English** · [Русский](./README.ru.md) · [简体中文](./README.zh-CN.md)
41
+
42
+ > **Renamed from `code-outline` in v0.3.0** to join the `ast-*` family convention popularised by [ast-grep](https://github.com/ast-grep/ast-grep). The legacy `code-outline` CLI command still works as a backward-compat alias through 0.4.x.
43
+
44
+ > Fast, AST-based **structural outline** for source files — classes, methods,
45
+ > signatures with line numbers, but **no method bodies**. Built for LLM coding
46
+ > agents that should read the *shape* of a file before reading the whole thing.
47
+
48
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
49
+ ![Python: 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)
50
+ ![Status: beta](https://img.shields.io/badge/status-beta-orange.svg)
51
+
52
+ ---
53
+
54
+ ## Purpose
55
+
56
+ **`ast-outline` exists to make LLM coding agents faster, cheaper, and smarter
57
+ when navigating unfamiliar code.**
58
+
59
+ Modern agentic coding tools (Claude Code, Cursor's agent mode, Aider,
60
+ Copilot Chat, custom CLI agents) explore codebases by reading files directly
61
+ — not via embeddings or vector search. That approach is reliable but has a
62
+ cost: on a 1000-line file, the agent pays for 1000 lines of tokens just to
63
+ answer *"what methods exist here?"*.
64
+
65
+ `ast-outline` closes that gap. It's a **pre-reading layer** for agents:
66
+
67
+ 1. **Token savings — typically 5–10×.** An outline replaces a full file
68
+ read when the agent only needs structural understanding.
69
+ 2. **Faster exploration.** A whole module's public API fits on one screen.
70
+ 3. **Precise navigation.** Every declaration has a line range (`L42-58`).
71
+ The agent goes straight to the method body it needs.
72
+ 4. **AST accuracy, not fuzzy match.** `implements` and `show` understand
73
+ real syntax — no false positives from comments or strings.
74
+ 5. **Zero infrastructure.** No index, no cache, no embeddings, no network.
75
+ Live, always fresh, invisible to your repo.
76
+
77
+ ### The typical agent workflow
78
+
79
+ **Before `ast-outline`:**
80
+
81
+ ```
82
+ Agent: Read Player.cs # 1200 lines of tokens
83
+ Agent: Read Enemy.cs # 800 lines of tokens
84
+ Agent: Read DamageSystem.cs # 400 lines of tokens
85
+ Agent: grep "IDamageable" src/ # noisy, lots of false matches
86
+ ...
87
+ ```
88
+
89
+ **With `ast-outline`:**
90
+
91
+ ```
92
+ Agent: ast-outline digest src/Combat # ~100 lines, whole module
93
+ Agent: ast-outline implements IDamageable # precise list, no grep noise
94
+ Agent: ast-outline show Player.cs TakeDamage # just the method body
95
+ ```
96
+
97
+ Result: **same understanding, a fraction of the tokens, a fraction of
98
+ the round-trips.**
99
+
100
+ ---
101
+
102
+ ## Supported languages
103
+
104
+ | Language | Extensions |
105
+ | --- | --- |
106
+ | C# | `.cs` |
107
+ | Python | `.py`, `.pyi` |
108
+ | TypeScript | `.ts`, `.tsx` |
109
+ | JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` (parsed by the TypeScript grammar) |
110
+ | Java | `.java` — classes, interfaces, `@interface`, enums, records, sealed hierarchies, generics, throws, Javadoc |
111
+ | Kotlin | `.kt`, `.kts` — classes, interfaces, `fun interface`, `object` / `companion object`, `data` / `sealed` / `enum` / `annotation` classes, extension functions, `suspend` / `inline` / `const` / `lateinit`, generics with `where` constraints, `typealias`, KDoc |
112
+ | Scala | `.scala`, `.sc` — Scala 2 + Scala 3: classes, traits, `object` / `case object`, `case class`, `sealed` hierarchies, Scala 3 `enum` / `given` / `using` / `extension`, indentation-based bodies, higher-kinded types, context bounds, `opaque type`, `type` aliases, Scaladoc |
113
+ | Go | `.go` — packages, structs (with method-grouping under receiver), interfaces, struct/interface embedding as inheritance, generics (Go 1.18+), `type` aliases + defined types, `iota` enum-blocks, doc-comment chains |
114
+ | Rust | `.rs` — modules (recursive), structs (regular / tuple / unit), unions, enums with all variant shapes, traits with supertraits as bases, **`impl` block regrouping under the target type** (inherent + `impl Trait for Foo` adds Trait to bases), `extern "C"` blocks, `macro_rules!`, type aliases, generics + lifetimes + `where` clauses, `pub` / `pub(crate)` visibility, outer doc comments (`///`, `/** */`) and `#[...]` attributes |
115
+ | Markdown | `.md`, `.markdown`, `.mdx`, `.mdown` — heading TOC + fenced code blocks |
116
+ | YAML | `.yaml`, `.yml` — key hierarchy with line ranges, `[i]` sequence paths, multi-document separators, format-detect for Kubernetes / OpenAPI / GitHub Actions in the header |
117
+
118
+ Adding another language is a single new adapter file. See
119
+ [`src/ast_outline/adapters/`](src/ast_outline/adapters/).
120
+
121
+ #### YAML caveats
122
+
123
+ Real-world YAML files routinely surface a `# WARNING: N parse errors`
124
+ header — `tree-sitter-yaml`'s strict parser flags fairly innocuous
125
+ inconsistencies (like a sequence item nested inside an unexpected
126
+ mapping context) and the error region can spread well beyond the
127
+ actual broken line. The adapter's recovery walk salvages most useful
128
+ structure around such regions; treat the outline as best-effort and
129
+ fall back to `Read` for the affected region when the answer is
130
+ load-bearing.
131
+
132
+ `show` for YAML matches **keys**, not value text. `show file.yaml
133
+ "some phrase"` will not find a phrase that lives inside a string
134
+ value — for free-text searches inside values, use `grep`/`rg`.
135
+ `ast-outline` is structural; it complements text search rather than
136
+ replacing it.
137
+
138
+ ---
139
+
140
+ ## Install
141
+
142
+ ### One-liner (recommended — macOS / Linux / Windows)
143
+
144
+ Requires [`uv`](https://docs.astral.sh/uv/) (a fast Python package manager):
145
+
146
+ ```bash
147
+ uv tool install git+https://github.com/dim-s/ast-outline.git
148
+ ```
149
+
150
+ This installs the `ast-outline` CLI globally into `~/.local/bin` (Mac / Linux)
151
+ or `%USERPROFILE%\.local\bin` (Windows) — make sure that's on your `PATH`.
152
+
153
+ Don't have `uv` yet?
154
+
155
+ ```bash
156
+ # macOS / Linux
157
+ curl -LsSf https://astral.sh/uv/install.sh | sh
158
+
159
+ # Windows (PowerShell)
160
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
161
+ ```
162
+
163
+ ### Using the install scripts in this repo
164
+
165
+ ```bash
166
+ # macOS / Linux
167
+ curl -LsSf https://raw.githubusercontent.com/dim-s/ast-outline/main/scripts/install.sh | bash
168
+
169
+ # Windows (PowerShell)
170
+ iwr -useb https://raw.githubusercontent.com/dim-s/ast-outline/main/scripts/install.ps1 | iex
171
+ ```
172
+
173
+ ### Alternative: `pipx`
174
+
175
+ ```bash
176
+ pipx install git+https://github.com/dim-s/ast-outline.git
177
+ ```
178
+
179
+ ### Alternative: `pip` (into an active venv)
180
+
181
+ ```bash
182
+ pip install git+https://github.com/dim-s/ast-outline.git
183
+ ```
184
+
185
+ ### Update / uninstall
186
+
187
+ ```bash
188
+ uv tool upgrade ast-outline
189
+ uv tool uninstall ast-outline
190
+ ```
191
+
192
+ ---
193
+
194
+ ## Quick start
195
+
196
+ ```bash
197
+ # Structural outline of one file
198
+ ast-outline path/to/Player.cs
199
+ ast-outline path/to/user_service.py
200
+
201
+ # Outline a whole directory (recurses supported extensions)
202
+ ast-outline src/
203
+
204
+ # Print the source of one specific method
205
+ ast-outline show Player.cs TakeDamage
206
+
207
+ # Several methods at once
208
+ ast-outline show Player.cs TakeDamage Heal Die
209
+
210
+ # Compact public-API map of a whole module
211
+ ast-outline digest src/Services
212
+
213
+ # Every class that inherits/implements a given type
214
+ ast-outline implements IDamageable src/
215
+
216
+ # Built-in guide
217
+ ast-outline help
218
+ ast-outline help show
219
+ ```
220
+
221
+ ---
222
+
223
+ ## Using with LLM coding agents
224
+
225
+ This is the main use case. Add the snippet below to your `CLAUDE.md`,
226
+ `AGENTS.md`, subagent file, or any system prompt that steers a coding
227
+ agent. It will then prefer `ast-outline` over reading full files.
228
+
229
+ The same snippet ships with the tool — `ast-outline prompt` prints it
230
+ verbatim, so you can append it to a project's agent config without
231
+ copy-pasting:
232
+
233
+ ```bash
234
+ ast-outline prompt >> AGENTS.md
235
+ ast-outline prompt >> .claude/CLAUDE.md
236
+ ast-outline prompt | pbcopy # macOS clipboard
237
+ ```
238
+
239
+ ### Prompt snippet (copy-paste)
240
+
241
+ ```markdown
242
+ ## Code exploration — prefer `ast-outline` over full reads
243
+
244
+ For `.cs`, `.py`, `.pyi`, `.ts`, `.tsx`, `.js`, `.jsx`, `.java`, `.kt`, `.kts`,
245
+ `.scala`, `.sc`, `.go`, `.rs`, `.md`, and `.yaml`/`.yml` files, read structure
246
+ with `ast-outline` before opening full contents.
247
+
248
+ Stop at the step that answers the question:
249
+
250
+ 1. **Unfamiliar directory** — `ast-outline digest <paths…>`: one-page map
251
+ of every file's types and public methods. Each file is tagged with a
252
+ size label — `[tiny]` / `[medium]` / `[large]` — plus `[broken]`
253
+ when parse errors may have left the outline partial.
254
+
255
+ 2. **File-level shape** — `ast-outline <paths…>`: signatures with line
256
+ ranges, no bodies (5–10× smaller than a full read on non-trivial
257
+ files). A `# WARNING: N parse errors` line in the header means the
258
+ outline is partial — read the source for the affected region.
259
+
260
+ 3. **One method, type, markdown heading, or yaml key** —
261
+ `ast-outline show <file> <Symbol>`. Suffix matching: `TakeDamage`
262
+ for one method; `User` for an entire type — class, struct, interface,
263
+ trait, enum (whole body, useful when a file holds several types);
264
+ `Player.TakeDamage` when ambiguous. Multiple at once:
265
+ `ast-outline show Player.cs TakeDamage Heal Die`.
266
+ For markdown, the symbol is heading text and matching is
267
+ case-insensitive substring — `"installation"` finds
268
+ `"2.1 Installation (macOS / Linux)"`. For yaml, the symbol is a
269
+ dotted key path (`spec.containers[0].image`) — `show` matches keys,
270
+ not values, so for free-text search inside values use `grep`.
271
+
272
+ 4. **Who implements/extends a type** — `ast-outline implements <Type>
273
+ <paths…>`: AST-accurate (skip `grep`), transitive by default with
274
+ `[via Parent]` tags on indirect matches. Add `--direct` for level-1 only.
275
+
276
+ `outline`, `digest`, `implements` accept multiple paths in one call
277
+ (files and directories, mixed languages OK) — batch instead of looping.
278
+
279
+ Fall back to a full read only when you need context beyond the body
280
+ `show` returned. `ast-outline help` for flags.
281
+ ```
282
+
283
+ ### Why this helps
284
+
285
+ - **Fresh subagents with shallow context** (like Claude Code's `Explore`
286
+ agent) can scan a whole module in one call instead of 10–20 `Read`/`grep`
287
+ rounds.
288
+ - **"Where is X defined?"** becomes one `implements` or `show` call.
289
+ - **Line ranges** (`L42-58`) turn the outline into a precise navigator —
290
+ the agent reads only the lines it needs.
291
+ - **AST-based** `implements` has no false positives from string literals,
292
+ comments, or unrelated name mentions — unlike `grep`.
293
+
294
+ ### Works with
295
+
296
+ - Claude Code (+ custom subagents like `Explore`, `codebase-scout`)
297
+ - Cursor agent mode
298
+ - Aider
299
+ - Copilot Chat / Workspace
300
+ - Any custom agent on the Claude / OpenAI / Gemini APIs
301
+ - Humans (the format is readable; `show` is a nice alternative to `grep -A 20`)
302
+
303
+ ---
304
+
305
+ ## Commands
306
+
307
+ ### `outline` — default
308
+
309
+ Print the file's classes, methods, properties, fields with line ranges.
310
+
311
+ ```bash
312
+ ast-outline path/to/File.cs
313
+ ast-outline path/to/module.py --no-private --no-fields
314
+ ```
315
+
316
+ Flags:
317
+
318
+ - `--no-private` — hide private members (Python: names starting with `_`)
319
+ - `--no-fields` — hide field declarations
320
+ - `--no-docs` — hide `///` XML-doc / docstrings
321
+ - `--no-attrs` — hide `[Attributes]` / `@decorators`
322
+ - `--no-lines` — hide line-number suffixes
323
+ - `--glob PATTERN` — restrict directory mode to a pattern
324
+
325
+ ### `show` — extract source of a symbol
326
+
327
+ ```bash
328
+ ast-outline show File.cs TakeDamage
329
+ ast-outline show File.cs PlayerController.TakeDamage # disambiguate overloads
330
+ ast-outline show service.py UserService.get
331
+ ast-outline show File.cs TakeDamage Heal Die # several at once
332
+ ```
333
+
334
+ For code, matching is **suffix-based**: `Foo.Bar` matches any `*.Foo.Bar`. If
335
+ multiple declarations match, all are printed with a summary.
336
+
337
+ For markdown, matching is **case-insensitive substring** per dotted part.
338
+ LLM agents rarely remember the exact decoration of a heading (number prefixes
339
+ like `1.`, trailing `(Feb 2026)`, `(Confidence: 70%)`), so a fuzzy core works:
340
+
341
+ ```bash
342
+ ast-outline show forecast.md "current analysis"
343
+ # → matches `## 1. CURRENT ANALYSIS (Feb 2026)`
344
+
345
+ ast-outline show forecast.md "scenario.transit"
346
+ # → matches `### SCENARIO A: "MANAGED TRANSIT"` under any parent
347
+ # heading containing "scenario"
348
+ ```
349
+
350
+ If the substring matches several headings, all are printed and the
351
+ disambiguation summary lands on stderr — tighten the query to narrow.
352
+
353
+ ### `digest` — one-page module map
354
+
355
+ ```bash
356
+ ast-outline digest src/
357
+ ```
358
+
359
+ Sample output:
360
+
361
+ ```
362
+ # legend: name()=callable, name [kind]=non-callable, marker name()=method modifier (async/static/override/…), [N overloads]=N callables share name, [deprecated]=obsolete, L<a>-<b>=line range, : Base, …=inheritance
363
+ src/services/
364
+ __init__.py [tiny] (8 lines, ~74 tokens, 1 fields)
365
+ user_service.py [medium] (140 lines, ~1,200 tokens, 1 types, 5 methods)
366
+ @Service abstract class UserService [deprecated] : IUserService L8-138
367
+ async get(), async search(), abstract create(), delete(), update_v1() [deprecated]
368
+
369
+ auth_service.py [medium] (95 lines, ~840 tokens, 1 types, 4 methods)
370
+ [ApiController] sealed class AuthService L10-95
371
+ async login(), logout(), refresh(), override verify_token()
372
+
373
+ legacy_repo.py [large] [broken] (5234 lines, ~52,000 tokens, ...)
374
+ ```
375
+
376
+ The first line is a self-describing legend so an LLM can read the
377
+ output cold without `ast-outline prompt` loaded. Tokens follow the
378
+ universal programming-doc convention — `name()` for a callable,
379
+ `name [kind]` for a property/field/event/etc., method markers
380
+ (`async`, `static`, `abstract`, `override`, `virtual`, plus
381
+ language-native forms: Kotlin `open` / `suspend`, Python
382
+ `@staticmethod` / `@classmethod` / `@abstractmethod`, Java
383
+ `@Override`) prefix the name source-true so each language reads in
384
+ its own idiom. `[N overloads]` flags when several callables share a
385
+ name; `[deprecated]` whenever a type or member carries
386
+ `@Deprecated` / `[Obsolete]` / `#[deprecated]`. Type headers also
387
+ carry inline decorators / attributes (`@dataclass`, `[ApiController]`,
388
+ `#[derive(Debug)]`) and semantic modifiers (`abstract`, `sealed`,
389
+ `static`, `final`, `open`, `partial`) so runtime contracts and
390
+ instantiation rules read off at a glance. Members are joined with
391
+ `, `; types that have a body get a trailing blank line as a
392
+ paragraph break, empty types stack tightly so digest stays compact.
393
+ Source-language keywords (Rust `trait`, Scala `object`, Kotlin
394
+ `data class`) are preserved in the type header instead of the
395
+ canonical kind.
396
+
397
+ Each filename gets a descriptive size label — `[tiny]` (under ~500 tokens),
398
+ `[medium]` (500–5000), `[large]` (5000+). A `[broken]` marker appears next
399
+ to the size label when the parse hit syntax errors and the outline may be
400
+ partial. The labels describe the file; they don't prescribe an action.
401
+ An LLM agent reads them, weighs its task (does it need the whole file? a
402
+ single section? just structure?) and picks Read / outline / show accordingly
403
+ — the tool informs, the agent decides.
404
+
405
+ The label conventions live in the canonical agent prompt (`ast-outline prompt`)
406
+ so they're paid for once per session, not on every digest call. Size class is
407
+ calibrated against an approximate token count (`len(chars)/4`, ±15-20% vs
408
+ real BPE tokenizers — fine for the heuristic). The same `~N tokens` count
409
+ appears in every `outline` header too.
410
+
411
+ ### `implements` — find subclasses / implementations
412
+
413
+ ```bash
414
+ ast-outline implements IDamageable src/
415
+ ```
416
+
417
+ AST-based — no false positives from comments or unrelated mentions.
418
+ **Transitive by default**: if `Puppy extends Dog extends Animal`, then
419
+ `implements Animal` returns all three, with an annotation on indirect
420
+ matches:
421
+
422
+ ```
423
+ # 3 match(es) for 'Animal' (incl. transitive):
424
+ src/Animals.cs:5 class Dog : Animal
425
+ src/Cats.cs:3 class Cat : Animal
426
+ src/Puppies.cs:12 class Puppy : Dog [via Dog]
427
+ ```
428
+
429
+ Add `--direct` / `-d` to restrict to level-1 subclasses only:
430
+
431
+ ```bash
432
+ ast-outline implements --direct IDamageable src/
433
+ ```
434
+
435
+ The search works across any number of files and nested directories —
436
+ no reliance on filename↔classname convention. Matching is by the last
437
+ segment of the type name (stripping generics and namespace prefixes).
438
+
439
+ ### `prompt` — print the agent prompt snippet
440
+
441
+ ```bash
442
+ ast-outline prompt
443
+ ast-outline prompt >> AGENTS.md
444
+ ```
445
+
446
+ Prints the canonical copy-paste snippet used to steer LLM coding agents
447
+ to prefer `ast-outline` over full reads. English, universal across
448
+ Claude Opus 4.7 / Sonnet 4.6 / Haiku 4.5. Running it ensures you always
449
+ get the current recommended version.
450
+
451
+ ---
452
+
453
+ ## Output format
454
+
455
+ The format is designed to be **LLM-friendly**: Python-style indentation,
456
+ line-number suffixes in `L<start>-<end>` form, doc-comments preserved.
457
+ The header summarises scale and flags partial parses.
458
+
459
+ ### C#
460
+
461
+ ```
462
+ # Player.cs (142 lines, 3 types, 12 methods, 5 fields)
463
+ namespace Game.Player
464
+ [RequireComponent(typeof(Rigidbody2D))] public class PlayerController : MonoBehaviour, IDamageable L10-120
465
+ [SerializeField] private float speed = 5f L12
466
+ public int CurrentHealth { get; private set; } L15
467
+ /// <summary>Apply damage.</summary>
468
+ public void TakeDamage(int amount) L30-48
469
+ private void Die() L50-55
470
+ ```
471
+
472
+ ### Python
473
+
474
+ ```
475
+ # user_service.py (70 lines, 2 types, 5 methods, 3 fields)
476
+ @dataclass class User L16-29
477
+ def display_name(self) -> str L26-29
478
+ """Human-friendly label."""
479
+
480
+ class UserService L31-58
481
+ def __init__(self, storage: Storage) -> None L34-35
482
+ def get(self, user_id: int) -> User | None L37-42
483
+ """Look up a user by id."""
484
+ def save(self, user: User) -> None L44-46
485
+ ```
486
+
487
+ ### `show` with ancestor context
488
+
489
+ `ast-outline show <file> <Symbol>` prints a `# in: ...` breadcrumb
490
+ between the header and the body so you know what the extracted code is
491
+ nested inside, without a second `outline` call:
492
+
493
+ ```
494
+ # Player.cs:30-48 Game.Player.PlayerController.TakeDamage (method)
495
+ # in: namespace Game.Player → public class PlayerController : MonoBehaviour, IDamageable
496
+ /// <summary>Apply damage.</summary>
497
+ public void TakeDamage(int amount) { ... }
498
+ ```
499
+
500
+ Top-level symbols (no enclosing namespace/type) have no breadcrumb.
501
+
502
+ ### Partial parses
503
+
504
+ When tree-sitter recovers from syntax errors, the outline is kept but a
505
+ second header line flags the gap:
506
+
507
+ ```
508
+ # broken.java (16 lines, 1 types, 3 methods)
509
+ # WARNING: 3 parse errors — output may be incomplete
510
+ ```
511
+
512
+ Agents should treat these files as partial and read the source directly
513
+ for the affected region.
514
+
515
+ Differences are language-idiomatic:
516
+
517
+ - C# `///` XML-doc appears **above** the signature.
518
+ - Python `"""docstrings"""` appear **below** the signature with one extra
519
+ indent (matching Python semantics).
520
+ - C# attributes (`[Attr]`) and Python decorators (`@foo`) are inlined with
521
+ the declaration.
522
+ - C# property accessors `{ get; private set; }` are preserved.
523
+
524
+ ---
525
+
526
+ ## How it works (briefly)
527
+
528
+ - Parses source with [tree-sitter](https://tree-sitter.github.io/) —
529
+ real AST, not regex.
530
+ - Language-specific adapters convert the AST to a uniform
531
+ `Declaration` intermediate representation.
532
+ - Language-agnostic renderers produce outline / digest / search output.
533
+ - Purely local, no network, no indexing, no cache — just reads and parses
534
+ the files you ask about.
535
+
536
+ No vector database, no embedding, no RAG. This is deliberate — the philosophy
537
+ matches how agentic coding tools like Claude Code actually work.
538
+
539
+ ---
540
+
541
+ ## Development
542
+
543
+ ```bash
544
+ git clone https://github.com/dim-s/ast-outline.git
545
+ cd ast-outline
546
+
547
+ # Create a venv and install in editable mode
548
+ uv venv
549
+ uv pip install -e .
550
+
551
+ # Run against the included samples
552
+ .venv/bin/ast-outline tests/sample.cs
553
+ .venv/bin/ast-outline tests/sample.py
554
+ .venv/bin/ast-outline digest tests/
555
+ ```
556
+
557
+ ### Running the tests
558
+
559
+ Tests are an optional dev dependency — end users don't pull them in. Install
560
+ them once and run via `pytest`:
561
+
562
+ ```bash
563
+ # Install pytest into the same venv as the editable install
564
+ uv pip install -e ".[dev]"
565
+
566
+ # Run the full suite (takes ~0.1s)
567
+ .venv/bin/pytest
568
+
569
+ # Just one file, verbose
570
+ .venv/bin/pytest tests/unit/test_csharp_adapter.py -v
571
+
572
+ # Match by test name
573
+ .venv/bin/pytest -k file_scoped_namespace -v
574
+ ```
575
+
576
+ The suite (600+ tests) covers every adapter (C#, Python, TypeScript/JS,
577
+ Java, Kotlin, Scala, Go, Rust, Markdown, YAML), the language-agnostic
578
+ renderers, symbol search, and the CLI end-to-end. Fixtures live under `tests/fixtures/`;
579
+ tests never reach outside that directory.
580
+ New behaviour should come with a test; new languages should ship with a
581
+ dedicated fixture directory and a `tests/unit/test_<lang>_adapter.py` file.
582
+
583
+ ### Adding a new language
584
+
585
+ Create `src/ast_outline/adapters/<lang>.py` implementing the
586
+ `LanguageAdapter` protocol (see `adapters/base.py`). Then register it in
587
+ `adapters/__init__.py`. The core renderers and CLI pick it up automatically
588
+ — no further wiring needed.
589
+
590
+ ---
591
+
592
+ ## Roadmap
593
+
594
+ - [x] TypeScript / JavaScript adapter (`.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`, `.cjs`)
595
+ - [x] Java adapter (`.java`) — classes, interfaces, `@interface`, enums, records, sealed hierarchies, generics, throws, Javadoc
596
+ - [x] Kotlin adapter (`.kt`, `.kts`) — classes, interfaces, `fun interface`, `object` / `companion object`, `data` / `sealed` / `enum` / `annotation` classes, extension functions, `suspend` / `inline` / `const` / `lateinit`, generics with `where` constraints, `typealias`, KDoc
597
+ - [x] Scala adapter (`.scala`, `.sc`) — Scala 2 + Scala 3: classes, traits, `object` / `case object`, `case class`, `sealed` hierarchies, Scala 3 `enum` / `given` / `using` / `extension`, indentation-based bodies, higher-kinded types, context bounds, `opaque type`, `type` aliases, Scaladoc
598
+ - [x] Go adapter (`.go`) — packages, structs (with method-grouping under receiver), interfaces, struct/interface embedding as inheritance, generics (Go 1.18+), `type` aliases + defined types, `iota` enum-blocks, doc-comment chains
599
+ - [x] Rust adapter (`.rs`) — modules (recursive), structs (regular / tuple / unit), unions, enums with all variant shapes, traits + supertraits as bases, **`impl` block regrouping under the target type** (inherent + `impl Trait for Foo` adds Trait to bases), `extern "C"` blocks, `macro_rules!`, type aliases, generics + lifetimes + `where` clauses, full visibility classifier (`pub` / `pub(crate)` / `pub(super)` / `pub(in path)`), outer doc comments + `#[...]` attributes
600
+ - [x] Markdown adapter (`.md`, `.markdown`, `.mdx`, `.mdown`) — heading TOC + code blocks
601
+ - [x] YAML adapter (`.yaml`, `.yml`) — key hierarchy, `[i]` sequence paths, multi-document support, format-detect for Kubernetes / OpenAPI / GitHub Actions
602
+ - [ ] `--format json` output mode for programmatic consumers
603
+ - [ ] Optional multiprocessing for very large codebases (>500 files)
604
+
605
+ Contributions welcome.
606
+
607
+ ---
608
+
609
+ ## License
610
+
611
+ [MIT](./LICENSE)