| Crates.io | awful_rustdocs |
| lib.rs | awful_rustdocs |
| version | 0.2.0 |
| created_at | 2025-09-02 08:45:44.776905+00 |
| updated_at | 2025-09-04 13:35:36.623583+00 |
| description | Generate Rustdoc comments automatically using Awful Jade and a Nushell-based AST extractor. |
| homepage | https://github.com/graves/awful_rustdocs |
| repository | https://github.com/graves/awful_rustdocs |
| max_upload_size | |
| id | 1820820 |
| size | 3,093,375 |
Awful Rustdocs is a CLI that generates or improves Rustdocs for your codebase by harvesting symbols with a rust_ast.nu, enriching per-item context using ast-grep, and asking Awful Jade to draft concise, high-quality docs.
It can write the docs back into your source files in the correct location while preserving attributes like #[derive(...)], #[serde(...)], etc.

It supports:
--only (case-sensitive, matches simple name or fully qualified path).--overwrite off by default.You provide (or use the default) Nu script rust_ast.nu that emits a list of items (at least fn and struct) with fields like:
kind ("fn", "struct")file, fqpath, name, visibilitysignature (the item line the user would see)span (start/end line/byte)doc (existing comment, if any)body_text (item body where present)callers (if your pipeline includes it)These rows are read by Awful Rustdoc and grouped per file.
For functions (unless disabled):
(A::B, A::<T>::B, A::{...}) discovered by pattern queries.These additional hints help the LLM write better docs.
Two templates are loaded from your Awful Jade template directory:
--template (default: rustdoc_fn): for functions--struct-template (default: rustdoc_struct): for structs + fieldsThe struct template is expected to specify a response_format JSON schema. The model returns structured JSON that contains:
fields[] (name + rustdoc text) to be inserted inline.You have full control over wording and constraints in those templates.
For each item:
/// block.response_format schema (see next section), from which the program extracts:/// block),/// line or short block).All model output is passed through sanitizers:
strip_wrappers_and_fences_strict: safely removes wrapper tokens (e.g., ANSWER:) only when they appear at line starts and outside fences; it won’t nuke inline code examples.sanitize_llm_doc: converts any prose to strict /// lines; trims double-blanks; balances fences; removes a leading empty /// if present.For each edit, the patcher:
#[derive], #[serde]) so the doc block sits at the very top, preserving the attribute group below.--overwrite is set.target/llm_rustdocs/docs.json.The program will:
/// block placed above any attribute lines that decorate the struct.fields[].doc as /// immediately above the corresponding field, with the field’s current indentation and preserving any field attributes below the doc.Requirements:
rust-ast.nuast-grep (CLI) for call/path discovery in functions--config, --template, --struct-template)You’ll need:
winget install Rustlang.Rustupbrew install nushellsnap install nushell --classic or cargo install nuwinget install nushellast-grep (CLI)
brew install ast-grepast-grep-cliast-grep or download release💡 Tip: Verify all dependecies are installed.
cargo --version
nu --version
ast-grep --version
cargo install awful_rustdoc
This installs the awful_rustdoc binary into ~/.cargo/bin. Make sure that directory is on your PATH.
Run once to install the default config and templates into Awful Jade’s configuration directory:
awful_rustdoc init
Use --force to overwrite existing files, or --dry-run to preview what would be written.
By default, files are placed under the standard platform-specific config directory:
~/Library/Application Support/com.awful-sec.aj/~/.config/awful_jade/%APPDATA%\awful_jade\Do you want me to add a short table showing exactly which files (rustdoc_config.yaml, rustdoc_fn.yaml, rustdoc_struct.yaml) end up in those directories after init?
rust_ast.nuYour binary defaults to --script rust_ast.nu (looked up in the current working directory). Place it in your repo root or wherever you’ll run the command from.
http get https://raw.githubusercontent.com/graves/nu_rust_ast/HEAD/rust_ast.nu | save rust_ast.nu
Or git clone https://github.com/graves/nu_rust_ast and copy rust_ast.nu from there. I prefer to have it saved in my $"($nu.data-dir)/scripts" directory and sourced by $nu.config-file to use the functions it provides whenever I need them.
From your project root (where rust_ast.nu now lives):
awful_rustdoc --limit 1
You should see target/llm_rustdocs/docs.json produced. This confirms the harvesting pipeline and template loads are working. Nothing is written to your source files unless you add --write.
If you hit any bumps, ping me with the error output and the snippet—you’ve already got a solid pipeline, so it’s typically a problem with the templates or config.
λ awful_rustdocs run --help
(default) Generate rustdocs using current options
Usage: awful_rustdocs run [OPTIONS] [TARGETS]...
Arguments:
[TARGETS]... Paths (files/dirs) to analyze (default: ".")
Options:
--script <SCRIPT>
Path to your rust_ast.nu (the Nu script you shared) [default: rust_ast.nu]
--write
Write docs directly into source files (prepending ///)
--overwrite
Overwrite existing rustdoc if present (default: false; only fills missing)
--session <SESSION>
Session name for Awful Jade; if set, enables memory/session DB
--limit <LIMIT>
Limit the number of items processed (for testing)
--no-calls
Skip per-function ast-grep call-site analysis
--no-paths
Skip per-function qualified path analysis
--fn-template <FN_TEMPLATE>
Template for functions (expects response_format JSON) [default: rustdoc_fn]
--struct-template <STRUCT_TEMPLATE>
Template for structs+fields (expects response_format JSON) [default: rustdoc_struct]
--config <CONFIG>
Awful Jade config file name under the app config dir (changed default to match the new init filename) [default: rustdoc_config.yaml]
--only <SYMBOL>...
Only generate docs for these symbols (case-sensitive)
-h, --help
Print help
awful_rustdoc
Artifacts go to target/llm_rustdocs/docs.json.
src/.awful_rustdoc src --write
awful_rustdoc --write --overwrite
awful_rustdoc --only do_work --write
awful_rustdoc --only my_crate::utils::do_work --write
awful_rustdoc --only my_crate::types::Config --write
#[derive], #[serde], …) so attributes remain directly attached to the struct item.fn signature.--overwrite (default), items that already have docs are skipped.--overwrite, the existing doc lines are replaced.target/llm_rustdocs/docs.json — a structured dump of everything generated:[
{
"kind": "fn",
"fqpath": "...",
"file": "src/...rs",
"start_line": 123,
"end_line": 167,
"signature": "pub fn ...",
"callers": ["..."],
"referenced_symbols": ["..."],
"llm_doc": "/// lines...\n/// ...",
"had_existing_doc": false
}
]
rustdoc_fn):
/// block (no backticks, no prose outside).Parameters:, Returns:, Errors:, Safety:, Notes:, Examples:///.rustdoc_struct):
fields[] array.response_format.Your --struct-template should define a strict response_format similar to:
response_format:
name: rustdoc_struct_v1
strict: true
description: Rust struct docs plus per-field inline docs.
schema:
type: object
properties:
doc:
type: string
description: A short 1–2 sentence struct summary. No headings, no lists. Pure prose.
fields:
type: array
description: Inline field docs. Ignored if field name not found in struct body.
items:
type: object
properties:
name:
type: string
description: Field identifier exactly as it appears in the struct.
doc:
type: string
description: The rustdoc content for this field (one or a few `///` lines of prose).
required: [name, doc]
required: [doc, fields]
Your system_prompt, pre, post user messages should instruct the model to:
///.///./// if present./// ```rust … ///),#[...] blocks untouched. If you see attributes removed, verify your template didn’t emit attribute-like text and that you’re not running another formatter concurrently.response_format constraints and system rules; consider enabling strict: true.fields[] array with exact field names as they appear in the code. The patcher only inserts for names it can find.-no-calls and/or --no-paths to skip ast-grep passes.CC0-1.0