Architecture documents for firmware usually end up in a Word file. It lives on a shared drive, away from the code. Nobody can see what changed between two versions, and the diagrams are pasted images that someone has to redraw by hand. After a year, the document describes a system that no longer exists.
Docs-as-code fixes that. The architecture is written as plain text, sits in the same Git repository as the firmware, and changes in the same pull request as the code it describes. For documents with real structure (numbered chapters, cross-references, diagrams, a PDF for sign-off), AsciiDoc is the format I use.
In this article I set up the toolchain step by step, show how an arc42 document is split into files, and explain what you get in review that a Word file can never give you.
1. AsciiDoc is the language, Asciidoctor is the tool
The mental model: Markdown’s bigger sibling, built for long documents.
AsciiDoc is a plain-text markup language. Like Markdown, it reads well as source. Unlike Markdown, it has the structure a long technical document needs built in: numbered sections, an automatic table of contents, cross-references, includes, admonitions (NOTE, TIP, WARNING) and diagram blocks.
Asciidoctor is the open-source processor that turns .adoc files into HTML5, PDF,
DocBook and other formats. The reference version runs on Ruby; there are also JavaScript
(Asciidoctor.js) and JVM (AsciidoctorJ) builds.
| Need | Markdown | AsciiDoc |
|---|---|---|
| Table of contents and section numbers | needs extra tooling | built in (:toc:, :sectnums:) |
| Cross-references | manual anchors | built in (<<section-id>>) |
| Split a document into files | no | include::chapter.adoc[] |
| Admonitions (NOTE, WARNING) | no | built in |
| Diagrams from text | depends on the renderer | asciidoctor-diagram |
| PDF output | external tooling | asciidoctor-pdf |
For a README, Markdown is fine. For a document with twelve chapters and a sign-off, it is not.
2. Install the toolchain
Four pieces: Ruby, Asciidoctor with two extensions, Java for PlantUML, and an editor preview.
Ruby. On Windows, use RubyInstaller and pick a “Ruby+Devkit” build. Keep “Add Ruby to
PATH” checked, and at the end let it run ridk install with the MSYS2 development
toolchain. On macOS and Linux, use the package manager:
brew install ruby # macOS (Homebrew)
sudo apt-get install ruby-full # Debian / UbuntuAsciidoctor and its extensions:
gem install asciidoctor # the processor, HTML output
gem install asciidoctor-pdf # PDF output
gem install asciidoctor-diagram # diagram blocks (PlantUML and others)
asciidoctor --versionJava, for PlantUML. asciidoctor-diagram calls PlantUML to render diagram blocks, and
PlantUML runs on Java. Install a current JDK or JRE (for example from Adoptium) and check
java -version. Some PlantUML diagram types also need Graphviz; the PlantUML
documentation lists which.
Editor preview. In VS Code, install the “AsciiDoc” extension published by asciidoctor.
Open an .adoc file and open the preview beside it (Ctrl+Shift+V).
Check where your diagrams are rendered
3. Write and build a first document
Create architecture.adoc:
= Software Architecture
Your Name <you@example.com>
:toc: left
:sectnums:
:icons: font
== Introduction and Goals
The firmware runs on a Cortex-M7 microcontroller.
TIP: Admonitions like TIP, NOTE and WARNING render as styled callouts.
== Building Block View
[plantuml, building-blocks, svg]
----
@startuml
component Application
component Comms
component Storage
Application --> Comms
Application --> Storage
@enduml
----Build it:
asciidoctor -r asciidoctor-diagram architecture.adoc # architecture.html
asciidoctor-pdf -r asciidoctor-diagram architecture.adoc # architecture.pdfThe -r asciidoctor-diagram option loads the extension. On each build it renders the
PlantUML block to an SVG and places it in the document. You never draw a box by hand.
4. Structure it as arc42
The mental model: arc42 tells you what to write; AsciiDoc tells you how to split it.
arc42 is a widely used template for software architecture documentation. It has twelve chapters, from goals and constraints to risks and a glossary, and it is published in an AsciiDoc version.
Give each chapter its own file and pull them together in one master file with include::.
A change to the runtime view then touches one small file, and the pull request stays
readable.
For firmware, a few chapters do most of the work:
- Building block view: the static structure: components, tasks or active objects, and their interfaces.
- Runtime view: the important scenarios over time, as sequence diagrams: start-up, an update, a fault.
- Deployment view: which software runs on which board, MCU and memory.
- Architecture decisions: why you chose what you chose. The reason is the part that gets lost first.
Start small
5. Review it like code
This is the real payoff. Because the document and its diagrams are text, a change shows up in the pull request as a diff, line by line.
Two habits make it stick:
- Change the architecture in the same pull request as the code. If a new component appears in the code, it appears in the building block view in the same review.
- Build the documents in CI. Run the same two
asciidoctorcommands on every push, so a broken include or diagram fails the build, and the latest HTML and PDF are always available.
Commit the source, not the output
.adoc files and the diagram text in Git. Treat the generated HTML, PDF and
diagram images as build output, the same way you treat a firmware binary.6. Licences
Everything in the core toolchain is free and open source. Check the terms yourself before you rely on them, but this is the picture:
| Component | Licence |
|---|---|
| AsciiDoc (the language) | open specification, developed at the Eclipse Foundation |
| Asciidoctor, asciidoctor-pdf, asciidoctor-diagram | MIT |
| VS Code AsciiDoc extension | MIT |
| PlantUML | available under several licences, including GPL and LGPL |
| arc42 template | Creative Commons |
MIT is permissive: you can use the tools in commercial and closed-source work. PlantUML runs as a separate program that produces images; its website explains the terms for those images.
Summary
- Write architecture as text, next to the code. AsciiDoc gives long documents the structure Markdown lacks, and Asciidoctor turns one source into HTML and PDF.
- Use arc42 for the structure. One file per chapter, one master file with
include::, and start with the chapters that carry the most weight. - Review it like code. Diagrams as text, changes in the same pull request as the code, and a CI build that keeps the output current.
Sources
- Asciidoctor documentation: asciidoctor, asciidoctor-pdf and asciidoctor-diagram.
- arc42 documentation and templates (arc42.org).
- PlantUML documentation (plantuml.com).
- AsciiDoc language specification work at the Eclipse Foundation (AsciiDoc Working Group).
- Kroki documentation (kroki.io).
💬 Questions, corrections, or your own war story? Leave a comment below.
💬 Discussion
Questions, corrections, or war stories from your own board? Leave a comment below — I read and answer all of them. (Sign-in with GitHub.)