✅ fresh
last synced 2026-06-17T22:39:35.514075+00:00 · coverage 100% (
doc-generator)Validation by Beadloom
doc_sync— same source assync-check.
doc-generator
Doc skeleton generation + AI polish data from architecture graph
Source
src/beadloom/onboarding/doc_generator.py
Overview
Generates documentation skeletons from the architecture graph, and produces structured data for AI agents to enrich those skeletons. Part of the beadloom init --bootstrap pipeline and available as standalone CLI commands (beadloom docs generate, beadloom docs polish) and MCP tool (generate_docs).
Public API
| Function | Description |
|---|---|
generate_skeletons(project_root, nodes?, edges?) | Create docs/ tree from graph: architecture.md, domain READMEs, service pages, feature SPECs. Loads symbols from SQLite for Public API sections. Writes docs: field back to services.yml via _patch_docs_field(). |
generate_polish_data(project_root, ref_id?) | Return structured JSON (nodes with symbols/deps/existing docs, Mermaid diagram, AI enrichment prompt). Enriches with SQLite dependency edges via _enrich_edges_from_sqlite(). |
format_polish_text(data) | Render polish data as multi-line human-readable text with node details, symbols, deps, doc status. |
Generated File Types
| Path | Node Kind | Content |
|---|---|---|
docs/architecture.md | — | Domains table, services table, Mermaid dependency map |
docs/domains/{name}/README.md | domain | Summary, source, public API, dependencies, features list |
docs/services/{name}.md | service | Summary, source, public API, dependencies |
docs/domains/{parent}/features/{name}/SPEC.md | feature | Summary, source, public API, dependencies, parent domain |
Path Resolution
Doc paths are determined by _doc_path_for_node() with two-level priority:
docs:field — if the graph node has an explicitdocs:list, the first entry is used- Convention fallback —
domains/{ref_id}/README.md,services/{ref_id}.md,domains/{parent}/features/{ref_id}/SPEC.md
Root service node (no part_of edge as src) is skipped — covered by architecture.md.
docs: Writeback
After creating skeleton files, generate_skeletons() writes docs: field back to services.yml via _patch_docs_field(graph_dir, docs_map):
- Collects
{ref_id: relative_doc_path}for all newly created files only - Reads each
.ymlin graph directory (skipsrules.yml) - Adds
docs: [path]to nodes that don't already have the field - Writes each
.ymlatomically viawrite_yaml_atomic(yml, data, sort_keys=False, allow_unicode=True)(the atomic-io primitive — temp file +fsync+os.replace), so an interrupted writeback never leaves a truncatedservices.yml.sort_keys=Falsepreserves key ordering; output bytes are identical to the prior directyaml.dump.
This ensures _build_doc_ref_map() in reindex links docs to nodes correctly, so doctor reports real coverage.
SQLite Edge Enrichment
generate_polish_data() enriches node data with real dependency edges via _enrich_edges_from_sqlite():
- Opens
.beadloom/beadloom.db(read-only, best-effort) - Queries
edgestable fordepends_onedges (forward and reverse) - Merges into node data, deduplicating with YAML edges
- Graceful fallback when DB or
edgestable is missing
Skeleton Enrichment
When SQLite database exists (post-reindex), skeletons include:
- Public API table — public symbols (classes, functions) extracted from
code_symbols, filtered by source path prefix, private symbols (_-prefixed) excluded - Dependencies section —
depends_onandused_byedges (excluding structuralpart_of)
Internal Functions
| Function | Role |
|---|---|
_load_graph_from_yaml | Load nodes/edges from .beadloom/_graph/*.yml |
_find_root_node | Identify root service (no part_of as src) |
_doc_path_for_node | Resolve doc path from docs: field or convention |
_load_symbols_by_source | Best-effort SQLite symbol loading |
_render_symbols_section | Markdown table from public symbols |
_render_architecture | Domains + services tables + Mermaid |
_render_domain_readme | Domain page with features list |
_render_service | Service page with dependencies |
_render_feature_spec | Feature page with parent link |
_generate_mermaid | graph LR from depends_on/part_of edges |
_write_if_missing | Idempotent file writer |
_patch_docs_field | Write docs: back to graph YAML for newly created files |
_enrich_edges_from_sqlite | Read depends_on edges from SQLite into node data |
format_polish_text | Render polish data as human-readable multi-line text |
Design Decisions
- Never overwrites existing files (
_write_if_missing— idempotent, user edits preserved) <!-- enrich with: beadloom docs polish -->markers in all generated files- Standalone mode: loads graph from YAML when called without explicit nodes/edges
- Polish data includes code symbols from SQLite when available (post-reindex)
- Best-effort symbols with debug logging: SQLite errors (e.g., missing
code_symbolsornodestables) degrade gracefully without raising, but are logged at debug level for observability (UX#127) part_offiltering:_edges_for()excludes structural edges from dependency lists- docs: writeback: only for newly created files, never overwrites existing
docs:values
Testing
tests/test_doc_generator.py— unit tests for skeletons, mermaid, polish data, docs: writeback, SQLite edges, text format (37 tests)tests/test_cli_docs.py— CLIdocs generate/docs polish(8 tests)tests/test_integration_onboarding.py— end-to-end pipeline with idempotency (13 tests)
Parent
onboarding