16 KiB
Documentation Pass Spec
This doc is the persistent, canonical spec for the project-wide documentation pass. Re-read before each new pass.
Notes on doc placement
- (Moved below) See “Rustdoc style rules (strict)” for the general, idiomatic Rustdoc conventions to follow.
Process (imperative)
- Pick exactly one next module to work on (single file at a time); do not move on until it is fully documented.
- Work the file from top to bottom; do not skip ahead while leaving earlier items partially documented.
- After any context compaction or reset, re-read
docs/documentation-pass.mdanddocs/documentation-status.mdbefore continuing work. - Parallel sessions: before starting a module, claim it in
docs/documentation-status.mdwith your session number and date, then keep that claim updated until the module (and any tui/tui2 twin) is complete. - Start with the module doc (
//!) and draft the best available top-level narrative: responsibilities, non-responsibilities, state ownership, invariants, and how it fits the surrounding modules. - Then document every type, field, function, method, and non-obvious block in that module (public and private) with idiomatic Rustdoc.
- As you document lower-level items, promote any cross-cutting constraints or invariants up to the module doc (gravity well): update the module doc again after item-level docs to capture newly discovered constraints.
- When a struct or enum has multiple fields or helper methods, refresh its doc comment after field- and method-level docs to surface any newly discovered invariants or usage patterns.
- A module is “complete” only when: module docs are current, all items are documented, all field docs exist where meaningful, and comment-spacing rules are satisfied.
- If the module has a twin in
tui2, complete the matching file intui2in the same pass before moving on. - After each significant update, run
cargo docand capture any rustdoc warnings/lints; add new lint patterns to this document and todocs/documentation-status.mdso the pass is self-improving.
Single-module imperative prompt (follow in order)
- Open the file and read it top-to-bottom to understand the flow.
- Draft or improve the module doc (
//!) with responsibilities, non-responsibilities, ownership, and invariants. - Walk item-by-item in source order; add
///docs for every type, field, function, method, and non-obvious block. - For long functions or structs, expand docs beyond a single sentence with a short mechanism overview and lifecycle/ownership notes.
- Fix comment spacing (blank line before comment blocks, none after; no blank line after item headers).
- Refresh the module doc again to pull up any new constraints discovered while documenting items.
- Run
cargo docand record any new warning patterns so future passes preempt them.
Restarting the pass
- Always restart from
codex-rs/tuifirst. For this reset, focus only on the TUI crate. - Prefer deep-first: fully document one module (module doc + key items + field invariants + inline comments) before moving to the next module. Avoid broad header sweeps.
- After each module, check the current diff for removed docs in that module and restore them if they were inadvertently dropped (e.g., due to placement errors).
- Parallel sessions: do not switch modules without updating
docs/documentation-status.mdso other sessions can pick the next file without overlap.
You are performing a PROJECT-WIDE DOCUMENTATION PASS for a multi-crate Rust TUI codebase.
The goal is to produce a local version of this project where a developer can jump to any crate, module, type, function, or non-obvious block and immediately understand:
- what it does,
- why it exists,
- what invariants and contracts it relies on,
- who owns what state,
- and how it fits into the overall system.
This documentation pass should resemble the quality and depth of the Rust standard library and well-documented Rust crates such as tokio, axum, and ratatui: narrative first, precise contracts, idiomatic Rustdoc, minimal but high-signal inline comments.
Non-negotiable safety rules
You MUST:
- Not change runtime behavior.
- Not refactor logic.
- Not rename items or move code.
- Not change visibility (pub/private).
- Not alter async behavior, threading, or scheduling.
- Not change formatting except where needed to cleanly add documentation or comments.
You MAY:
- Add or edit Rustdoc comments (
//!and///). - Add or edit inline comments only where they clarify non-obvious logic, invariants, ordering constraints, or edge cases.
- Add Rustdoc intra-links and limited external links.
- Add examples only when they add real explanatory value.
If code changes are required to make the design clearer, list them as follow-ups but DO NOT implement them.
Rustdoc style rules (strict)
Write idiomatic Rust documentation:
-
Every documented item starts with a single-sentence summary.
-
Summary sentences should be grammatical and end with a period.
-
Follow with normal narrative paragraphs — no invented section headers like “Overview”, “Postconditions”, or “Misuse”.
-
Use Rustdoc headings ONLY when conventional and necessary:
# Errorswhen error meaning is non-trivial# Panicswhen panics are part of the contract# Safetyfor unsafe code or invariants# Examplesonly for important public APIs
-
Do NOT restate signatures, field names, or obvious control flow in prose.
-
For long or multi-step functions, extend the summary with a brief mechanism overview (the 2–4 key steps or phases) so readers without full context can follow the flow without reading the body.
-
When a long function performs multiple distinct responsibilities, prefer a short overview in the doc comment and add sparse inline comments to mark phase boundaries or non-obvious transitions.
-
If a one-line summary would be too terse for a reader without module context, add 1–3 more sentences that explain the core mechanism and what the function returns or mutates.
-
Apply the same “extra context” rule to long or high-impact structs, enums, and field groups: expand their doc comments with 2–4 sentences that explain lifecycle, ownership, and why the fields exist together.
-
For fields that are part of a larger state machine or lifecycle, add a short rationale line that ties them to the owning component’s responsibilities (who sets them, when they change, what they gate).
-
If a field represents a multi-step or multi-owner flow, add more than one sentence so a reader can understand where it is set, consumed, and how it affects behavior.
-
Prefer explaining mechanisms and invariants, not symptoms or hypothetical bugs.
- Write “Correctness relies on…” rather than “If this looks wrong…”.
General idiomatic Rustdoc conventions
- Module docs (
//!) belong at the top of the module file as the first non-empty line. - Item docs (
///) must appear immediately before the item (before any#[...]attributes). - When items have attributes (for example
#[inline],#[cfg(...)]), place the doc comment above the attributes, not between the attribute and the item. - Prefer Rust line doc comments (
//!////) over block doc comments (/** ... */). - Keep doc comments adjacent to the item they document; avoid trailing or floating docs.
- For field and item documentation, prefer
///unless the comment is a local, non-contract explanation scoped to a specific control-flow branch. - Use
//only for local, non-contract clarifications inside function bodies; if it describes ownership, invariants, or lifecycle, it belongs in///or//!. - Avoid bare
//section headers; prefer doc comments or remove if they add no information. - Leave a blank line before each comment block (doc comments and
//blocks), except immediately after an item header (e.g.,struct,enum,impl) where no extra blank line should be inserted. - Do not leave a blank line after a comment block; the comment should be immediately followed by the item or code it documents.
- Keep doc comments in active voice, avoid restating signatures, and prefer short paragraphs with explicit invariants and ownership notes.
- Headings and fenced code blocks must follow Markdown conventions with a blank line before and after the heading/code block so rustdoc renders them predictably.
- Use fenced code blocks for examples; omit the language tag for Rust, and add a tag only for plain text or other languages.
- Examples should compile; when they cannot, mark them with
no_runorignoreand briefly explain why in the surrounding prose. - If an intra-doc link is ambiguous, add a reference link at the end of the doc block:
- Example:
Textdescribes ...
- Example:
- Prefer intra-doc links to types and modules over prose re-explanations; use
crate::,super::, andSelf::where appropriate. - Use backticks for code identifiers, flags, and literals in prose.
- Use plural/singular consistently and avoid synonyms for the same concept within a module.
- Prefer Markdown over HTML in doc comments; use HTML only when Markdown cannot express the layout.
- If you add reference links, put them at the end of the doc block and separate them from the prose with a blank line.
- Avoid raw URLs in prose; prefer named links or reference links when possible.
- Avoid bare URLs: use angle-bracket auto links (
<https://...>) or reference links so rustdoc does not emitbare_urlswarnings. - Avoid literal angle-bracket placeholders like
<key>or<label>in prose; rustdoc treats them as HTML tags. Use backticks (`key`) or escape as<key>. - Avoid bracketed status tags like
[UNSTABLE]or[x]in plain text; rustdoc interprets them as links. Use backticks or escape[/]as\\[/\\]. - Ensure intra-doc links resolve: use fully-qualified paths when the type is not in scope, and prefer backticks if the target is private or intentionally unlinked.
Intra-doc links
- Prefer Rustdoc links like [
Type], [module::item], [Self::method]. - Use external links only for genuinely load-bearing specs (terminal behavior, protocols, standards).
Comment placement rules (gravity well rule)
-
Anything about architecture, layering, ownership, lifecycle, or invariants belongs in:
- crate-level docs (
//!in lib.rs / main.rs), - module-level docs (
//!), - or item docs (
///).
- crate-level docs (
-
Inline comments inside functions are ONLY for:
- tricky local logic,
- ordering constraints,
- platform quirks,
- edge cases,
- or intentionally surprising behavior.
Litmus test:
- If a comment would still be true if the function body were rewritten, it must be a doc comment, not an inline comment.
Coverage target
You are documenting the entire project, across all crates.
1) Workspace / crate-graph documentation (important)
At the workspace root or top-level crate docs, document:
- Each crate’s responsibility and non-responsibility
- How crates relate architecturally (layering, allowed dependency direction)
- Which crates define core concepts vs UI vs protocol vs integration
- Any invariants that span multiple crates
Treat crates as architectural layers, not just Cargo packages.
2) Crate-level documentation
For each crate:
- Purpose and scope
- Key concepts and terminology
- Main flows (happy path)
- Major non-goals
- How it interacts with other crates
- Where correctness invariants are enforced
- Where debugging typically starts (only stable, meaningful entry points)
3) Module-level documentation
For every non-trivial module, add or refine a //! header explaining:
- What problem the module solves
- Key concepts and terms
- Responsibilities vs non-responsibilities
- How it fits into surrounding modules
- Any state machine or lifecycle it manages
- Which components are responsible for enforcing invariants
Avoid API listings; write narrative explanations.
4) Public API documentation
For every public struct, enum, trait, function, and method:
- One-sentence summary
- Conceptual role in the system
- Invariants and contracts
- Ownership, mutability, and threading assumptions
- For
Result: what errors mean and what callers should do - Examples only when genuinely useful
5) Important internal items
For private but central components (state machines, caches, event routers, schedulers):
- Document like public APIs, but lighter
- Focus on ownership, invariants, and coupling points
- Explain why the abstraction exists
6) Field-level documentation (TUI-specific emphasis)
Document struct fields when:
- The meaning is not obvious from name/type
- The field participates in an invariant
- The field is a cache key, revision counter, tick, generation ID, or sentinel
For such fields, explain:
- What change it represents
- Who is responsible for updating it
- What breaks if it is not updated
These fields are part of the correctness contract even in private structs.
7) Event flow & state ownership (critical for TUIs)
For modules handling:
- input events,
- draw events,
- async streams,
- protocol events,
Document explicitly:
- Who owns the state
- Who may mutate it
- When mutation is allowed
- How synchronization with rendering is achieved
Avoid implicit ownership.
8) Terminal and platform assumptions
When behavior depends on:
- terminal capabilities,
- platform quirks,
- input modifiers,
- cursor or rendering behavior,
Document:
- The assumption being made
- Where it is handled or abstracted
- Whether it is a hard requirement or best-effort behavior
Do not describe symptoms; describe mechanisms and constraints.
9) Async rationale
For async code paths:
- Explain why async is required here
- Whether async is part of the public contract or an implementation detail
- How async tasks interact with UI or shared state
Prevent accidental blocking or cross-thread mutation assumptions.
10) Modes, overlays, and lifecycle
When code implements modes, overlays, or lifecycle transitions:
- Define what a “mode” means in this system
- Describe transition points
- State what data is preserved vs reset
- Document invariants that must hold across transitions
11) Inline comments
Add inline comments only for:
- non-obvious edge cases,
- ordering dependencies,
- intentional performance tradeoffs,
- platform-specific behavior,
- surprising but correct logic.
Avoid “what the code does” comments.
Depth calibration
Document to the level where a new contributor can:
- find the right abstraction quickly,
- understand the system’s shape,
- and reason about correctness without reverse-engineering call graphs.
Avoid:
- documenting trivial helpers,
- repeating code in prose,
- tutorial-style exposition in internal modules.
Bias toward documenting invariants, ownership, and lifecycle.
Work plan
- Workspace / crate-graph docs
- Crate-level docs
- Module-level docs
- Public API docs
- Key internal components
- Field-level invariant docs
- Selective inline comments
- Terminology consistency pass (prefer links over re-explanation)
Final output
Produce a patch that:
- adds crate, module, item, and field documentation,
- adds only high-signal inline comments,
- uses idiomatic Rustdoc and intra-links,
- avoids non-idiomatic labeled sections.
At the end, provide a short Follow-ups list:
- assumptions you had to guess,
- places where naming or structure blocks good docs,
- suggested future refactors (DO NOT implement).
You are not here to be polite — you are here to make the system legible.