Skip to content

fresh

last synced 2026-06-17T22:39:35.514075+00:00 · coverage 100% (doc-generator)

Validation by Beadloom doc_sync — same source as sync-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

FunctionDescription
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

PathNode KindContent
docs/architecture.mdDomains table, services table, Mermaid dependency map
docs/domains/{name}/README.mddomainSummary, source, public API, dependencies, features list
docs/services/{name}.mdserviceSummary, source, public API, dependencies
docs/domains/{parent}/features/{name}/SPEC.mdfeatureSummary, source, public API, dependencies, parent domain

Path Resolution

Doc paths are determined by _doc_path_for_node() with two-level priority:

  1. docs: field — if the graph node has an explicit docs: list, the first entry is used
  2. Convention fallbackdomains/{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 .yml in graph directory (skips rules.yml)
  • Adds docs: [path] to nodes that don't already have the field
  • Writes each .yml atomically via write_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 truncated services.yml. sort_keys=False preserves key ordering; output bytes are identical to the prior direct yaml.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 edges table for depends_on edges (forward and reverse)
  • Merges into node data, deduplicating with YAML edges
  • Graceful fallback when DB or edges table 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_on and used_by edges (excluding structural part_of)

Internal Functions

FunctionRole
_load_graph_from_yamlLoad nodes/edges from .beadloom/_graph/*.yml
_find_root_nodeIdentify root service (no part_of as src)
_doc_path_for_nodeResolve doc path from docs: field or convention
_load_symbols_by_sourceBest-effort SQLite symbol loading
_render_symbols_sectionMarkdown table from public symbols
_render_architectureDomains + services tables + Mermaid
_render_domain_readmeDomain page with features list
_render_serviceService page with dependencies
_render_feature_specFeature page with parent link
_generate_mermaidgraph LR from depends_on/part_of edges
_write_if_missingIdempotent file writer
_patch_docs_fieldWrite docs: back to graph YAML for newly created files
_enrich_edges_from_sqliteRead depends_on edges from SQLite into node data
format_polish_textRender 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_symbols or nodes tables) degrade gracefully without raising, but are logged at debug level for observability (UX#127)
  • part_of filtering: _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 — CLI docs generate / docs polish (8 tests)
  • tests/test_integration_onboarding.py — end-to-end pipeline with idempotency (13 tests)

Parent

onboarding