Skip to content

✅ fresh

last synced 2026-09-29T21:12:19.681221+00:00 · coverage 100% (doc-templates)

Validation by Beadloom doc_sync — same source as sync-check.

Doc Templates ​

The shape of a generated document — its template, its values, and the sections it requires.

Source: src/beadloom/onboarding/doc_templates.py


Specification ​

Purpose ​

Until BDL-061 S4b every doc skeleton was an f-string inside doc_generator.py. Two consequences followed, and both are why this module exists: an adopter had nothing to adapt — the shape of their architecture documentation was a Python literal inside our package — and nothing held the shape after generation, so a README could lose the sections it was born with and no check could tell.

The templates ship as package data under src/beadloom/onboarding/templates/docs/ and compose through compose(core, architecture, stack, project), the assembly S3 built for the role files. Reusing that mechanism rather than inventing a second one is what makes a project layer work for documents on the day it shipped for roles.

Doc kinds ​

KindGenerated fileNode kind
overviewdocs/architecture.md— (the project)
domaindocs/domains/<ref>/README.mddomain
servicethe service's pageservice
featuredocs/domains/<parent>/features/<ref>/SPEC.mdfeature
beadloom-readme.beadloom/README.md— (the project)

A kind with no node_kind describes the project rather than a node, so it has no doc-code pair and no sections to check it against.

Rendering ​

Placeholders use a doubled brace, deliberately not str.format's single brace:

text
# {{ref_id}}

> {{summary}}

A generated document carries Mermaid, JSON and shell fragments, and a lone { in any of them would either raise from the formatter or be eaten silently.

A placeholder with no value raises DocTemplateError. A silently-empty substitution is how a document ships half-written, which is the class unfilled-placeholder exists to report. A value the template does not use is allowed: an overlay is free to drop a fact it has no place for.

Required sections are derived, never declared twice ​

required_sections(kind) reads the literal ## headings of the composed template, with placeholders erased first. Two consequences follow from that one rule:

  • A project fragment at .beadloom/flow/docs/domain.md that appends ## Runbook makes Runbook a required section by the same act. That is PLAN's criterion "a project overlay can add required sections", met with one source of truth rather than two.
  • A heading that reaches the document through a placeholder — ## Public API, rendered only for a node with public symbols — is conditional by construction and cannot be required of a node that has none. ## Modules (the modules_section placeholder, BDL-069 S1) arrives the same way, and that is what lets the skeleton gain it without a single existing document being found to lack it on upgrade.

The same derivation, over the PLANNING documents ​

BDL-068 S1.4 extended the rule above to the other family of composed templates rather than building a second mechanism beside it. The BRIEF, RFC, PRD, CONTEXT, PLAN and ACTIVE skeletons are not docs artifacts at all — they are fenced blocks inside the composed /templates slash command, which is what the flow actually hands an author.

planning_skeletons() reads each ## <KIND>.md heading and the fenced blocks under it; required_sections_by_document_kind() runs the same section_titles extraction over them. Only the FENCED text is read: the prose around a skeleton is commentary, and reading it would make the commentary's own headings required of the document. A project fragment at .beadloom/flow/commands/templates.md that appends ## RUNBOOK.md with its own headings makes them required by the same act — the same property the node templates already had.

## Axes is required of a BRIEF and of an RFC because those two skeletons carry it. Nothing in code names the section.

A doc composition carries no suppression notice ​

ArtifactKind.carries_suppressions is False for docs. A declared suppression stands down a rule addressed to an agent; a generated README has no rules to stand down, and appending the notice would publish flow configuration as documentation.

Public API ​

SymbolKind
DOC_ARTIFACT_KINDconstant
DOC_KINDS / DOC_KIND_FOR_NODE_KINDconstant
DEFAULT_DOC_CONFIGconstant
DocKinddataclass
DocTemplateErrorexception
doc_templatefunction
doc_flow_configfunction
render_docfunction
PLANNING_TEMPLATEconstant
section_titlesfunction
required_sectionsfunction
required_sections_by_node_kindfunction
planning_skeletonsfunction
required_sections_by_document_kindfunction

Dependencies ​

  • Depends on: flow-composer (compose), flow-config
  • Used by: doc-generator, doc-shape-requirements, planning-report (through the join in application/doc_shape.py)

Parent ​

onboarding

Testing ​

tests/test_doc_templates.py — composition of every kind, the project layer, the derived sections, byte-identity of the extraction against the literals it replaced, and rendering for a project that is not Beadloom. tests/test_the_axes_section_is_required_by_the_template.py — the planning-document derivation: both kinds require Axes, only the fenced skeleton is read, and a project layer declaring its own document kind makes its sections required.