Extracts signatures and docstrings from a codebase so an agent can read the whole project in context — and open source files only where it needs to act.
A CLI tool that scans a codebase and generates a compact Markdown mirror of it, optimised for LLM consumption. Each source file becomes a .md file containing only its public interface — signatures, docstrings, and a link to the original. A global INDEX.md maps the full project tree with dual links to docs and source.
The source stays untouched. The mirror is small enough to load whole.
- Walks the codebase recursively, preserving directory structure
- Parses source files via AST — no LLM, no network, no runtime required
- Extracts the public interface: function and class signatures, docstrings, type annotations
- Filters private functions and methods — any function or method prefixed with
_is excluded; classes are always included - Generates a
.mdmirror: one file per source file, signatures only, link to original - Produces
INDEX.md: full project tree with dual links —.mddocs and source file for every node
The result is a representation an agent can read whole. When it needs to act on a specific part, it opens the source.
┌─────────────────────────────────────────────┐
│ Delivery Layer │
│ main.rs — CLI args, exit codes │
│ delivery/factories.rs — wires adapters │
│ into use cases │
└────────────────┬────────────────────────────┘
│ uses
┌────────────────▼────────────────────────────┐
│ Application Layer (Use Cases) │
│ FileScanner — walks filesystem, dispatches │
│ analyzers, builds ProjectLayout │
└────────────────┬────────────────────────────┘
│ uses
┌────────────────▼────────────────────────────┐
│ Infrastructure Layer (Adapters) │
│ ├── PythonParser (rustpython-parser) │
│ │ implements SourceCodeAnalyzer │
│ └── MarkdownWriter │
│ implements OutputWriter, │
│ IndexWriter │
└────────────────┬────────────────────────────┘
│ produces
┌────────────────▼────────────────────────────┐
│ Core Domain (Entities + Ports + Policies)│
│ entities/ DocumentedConstruct, │
│ ParsedSourceFile, ProjectLayout │
│ SourceFileAnalysis │
│ ports/ SourceCodeAnalyzer, ParserError │
│ OutputWriter, OutputWriterError │
│ IndexWriter │
│ policies/ ExclusionRules │
└─────────────────────────────────────────────┘
Dependency rule: arrows point inward only. The domain knows nothing of infrastructure or delivery.
Phase 1 — Scan
FileScanner walks the input directory with walkdir, collecting all source files. Each file is dispatched to the language-specific parser registered for its extension.
Phase 2 — Analyze
Each parser reads the file and runs an AST traversal — no execution, no import resolution, no network. It extracts every public construct: class signatures, method signatures, module-level functions, type annotations, and the first docstring of each. Private constructs (prefixed with _) are filtered out.
Phase 3 — Write
MarkdownWriter generates two outputs:
- A
.mdfile for each source file, placed in the mirror directory at the same relative path INDEX.mdat the root of the output, with the full project tree and dual links to docs and source
Given a project at ~/projects/myapp, running:
arcuate --input-dir ~/projects/myappProduces ~/projects/myapp/myapp_rq8_docs/:
myapp_rq8_docs/
├── INDEX.md
└── src/
├── calculator.md
└── utils.md
A generated .md file (src/calculator.md):
# calculator.py — Financial calculation utilities
## `class Calculator:`
> Class docstring here.
### `def add(a: float, b: float) -> float:`
> Returns the sum of two values.
### `def multiply(a: float, b: float) -> float:`
> Returns the product of two values.
## `def format_currency(amount: float, symbol: str = "$") -> str:`
> Formats a float as a currency string with the given symbol.INDEX.md:
# Index
- **src/** — Financial calculation utilities
- [calculator.py](src/calculator.md) — Financial calculation utilities · [source](/Users/you/projects/myapp/src/calculator.py)
- [utils.py](src/utils.md) · [source](/Users/you/projects/myapp/src/utils.py)Notes:
selfis stripped from method signatures- Source links in
INDEX.mduse absolute paths __init__.pyfiles are excluded from the index but their docstring annotates the parent directory
# Build and install both binaries globally
cargo install --path .
# Both commands are identical — use whichever you prefer
rq8 --input-dir ~/projects/myapp
arcuate --input-dir ~/projects/myappTwo equivalent commands are installed:
rq8 [--input-dir <path>] [--output-dir <path>] [exclusion flags]
arcuate [--input-dir <path>] [--output-dir <path>] [exclusion flags]| Flag | Default | Description |
|---|---|---|
--input-dir |
current directory | Root of the project to scan |
--output-dir |
<input-dir>/<dirname>_rq8_docs |
Where to write the generated Markdown files |
--exclude-dirs |
— | Comma-separated directory names to exclude (e.g. target,node_modules) |
--exclude-files |
— | Comma-separated file names to exclude (e.g. __init__.py) |
--exclude-dir-pattern |
— | Exclude dirs whose name starts with these prefixes (e.g. .,test) |
--exclude-file-pattern |
— | Exclude files whose name starts with these prefixes (e.g. .,test_) |
Examples:
# Scan current directory, output to ./<dirname>_rq8_docs
rq8
# Scan a specific project
rq8 --input-dir ~/projects/myapp
# Specify output directory
rq8 --input-dir ~/projects/myapp --output-dir ~/docs/myapp
# Exclude build artifacts and test files
rq8 --input-dir ~/projects/myapp --exclude-dirs target,node_modules --exclude-file-pattern test_arcuate/
├── src/
│ ├── main.rs # arcuate binary entry point
│ ├── rq8.rs # rq8 binary entry point (alias)
│ ├── application.rs
│ ├── application/
│ │ ├── file_scanner.rs # Walks filesystem, builds ProjectLayout
│ │ └── documentation_generator.rs # Orchestrates analysis and writing
│ ├── delivery.rs
│ ├── delivery/
│ │ ├── run.rs # Top-level orchestration
│ │ ├── factories.rs # Wires adapters into use cases
│ │ ├── mappers.rs
│ │ └── mappers/
│ │ └── cli_mapper.rs # Maps CLI args to domain objects
│ ├── domain.rs
│ ├── domain/
│ │ ├── entities.rs
│ │ ├── entities/
│ │ │ ├── definition_kind.rs
│ │ │ ├── documented_construct.rs
│ │ │ ├── parsed_source_file.rs
│ │ │ ├── project_layout.rs
│ │ │ └── source_file_analysis.rs
│ │ ├── policies.rs
│ │ ├── policies/
│ │ │ └── exclusion_rules.rs # File and directory exclusion logic
│ │ ├── ports.rs
│ │ └── ports/
│ │ ├── index_writer.rs
│ │ ├── output_writer.rs
│ │ ├── output_writer_error.rs
│ │ ├── parser_error.rs
│ │ └── source_code_analyzer.rs
│ ├── infrastructure.rs
│ └── infrastructure/
│ ├── markdown_writer.rs # implements OutputWriter + IndexWriter
│ └── python_parser.rs # AST parser — implements SourceCodeAnalyzer
└── Cargo.toml
Rust 2024 · rustpython-parser (AST) · walkdir (filesystem) · anyhow (errors)
MIT
--index-only flag.
Generate only INDEX.md without writing the full .md mirror. Useful when the project is large and the agent only needs navigation, not content.
New language parsers.
The SourceCodeAnalyzer port makes adding a language a matter of writing one adapter in infrastructure/. Rust and TypeScript are the natural next targets.
The arcuate fasciculus (fasciculus arcuatus, "arch-shaped bundle") is a white matter tract in the left cerebral hemisphere that connects two language regions:
- Broca's area — syntax, grammatical structure, language production
- Wernicke's area — semantic comprehension, word meaning
It arcs beneath the parietal cortex, curving around the Sylvian fissure. Its function is to act as a bidirectional bridge between syntactic and semantic processing. Without it, you can understand words and produce speech — but you cannot repeat sentences. The connection between comprehension and production is severed.
Arcuate (the tool) does the same thing:
| Arcuate fasciculus | Arcuate (tool) |
|---|---|
| Takes syntactic structure as input | Takes source code (language syntax) as input |
| Produces a semantic representation | Produces semantic documentation (signatures, docstrings, index) |
| Connects production and comprehension | Connects code to an agent's understanding of it |
| Is a bundle of fibres that doesn't expose the neurons | Produces documentation that doesn't expose the full source |
A bridge between syntax and semantics — exactly like the structure it's named after.
The tool also goes by rq8. Pronouncing each character individually — ar, kju, eɪt — reproduces the sound of the full word. The default output directory is named accordingly: <project>_rq8_docs.
