Docs as Code

One of the core principles of modern “DevOps” development is to treat your documentation as code, just like code. My team at Cisco open sourced how we do that.

Why Docs as Code

The ultimate documentation for any software project is the code itself. But for sets of code - especially today’s interconnected micro-services - having some kind of documentation is essential to being able to onboard new developers. More importantly, documentation is important for Operations. Not only is the system design needed, the details of how to deploy and operate complex software needs to be written down. Larger teams sometimes even have professional technical writers.

The best people to write the docs are the people who wrote the code. If you want writers to clean it up that’s fine. But the Engineers who built it know it best. So if for no other reason you should use tooling that the Engineers already use. But more on tooling later. The Engineers need to write code, and to make sure it’s accurate you should follow the same process as for code: do a code review on the documentation. And how do we do that? In git, of course. Github, to be specific.

We recommend (and mandate it in our teams) that the docs are reviewed by at least one additional qualified Engineer before it’s merged to master. This workflow is exactly what we do for code so it’s really easy to train on and roll out.

Why Not Word (or whatever)

Any word processor is going to be orthogonal to the workflow the Engineers are going to want to use. They are in a text editor all day, every day. If they are not you have different problems. They are in an editor and in github. Why break out of that to use a tool they don’t normally use?

In addition, word processors like Microsoft Word save in formats that are not friendly to git. If you want to read a pull request (PR) you don’t want a bunch of binary stuff in there: you want to see the change, and nothing but the change.


We settled on using markdown as our core text format. It’s easy to learn, easy to read, fully text based, git friendly, and most projects are already writing a README in it anyway. Why mess with a good thing?


We’ve had good luck with using either PlatUML and Graphviz. So far, for the kinds of diagrams we need to build those have done the trick. Whether we are building block diagrams, sequence diagrams, or entity-relationship diagrams, these tools do the trick. And they are still pure text, and git friendly.

Our Tooling - Compiling to Output

Since we are on a theme of doing docs as code, how do we “compile” the docs into desired output formats? Typical formats for consumption include HTML, PDF, and EPUB electronic book. This is where pandoc comes to the rescue. But installing the right tools and remembering how to use them was always difficult - especially to have the templates put together for formating.

We put all this together driven by makefile and the tools all dockerized. We creatively call this “Docs as Code” and Cisco approved releasing it open source.


The repo is a “template” repository. All you have to do is click the green “Use this template” button and instead of forking you can make a totally new repository using it as a template. You can then just work in that new repo.

There’s an example-template folder with a good working example. The overall template is in common/pandoc/templates but the default is pretty usable. You will want to make your own logo and drop it into common/images instead of the very ugly generic logo that we put there as a placeholder.

Change the title in the Makefile

To change the title of the output document, change the OUT_NAME in the Makefile:

OUT_NAME := example-template

include ../common/Makefile

Setting the Document Attributes

To change the title, subtitle, and to control the various document attributes you can edit the “pp” directives in the file:

title: The Title
subtitle: 0.1.0 - Confidentiality Statement Goes Here
author: ["First Author1", "Second Author2"]
titlepage: true
toc-title: Table of Contents
logo: ../common/images/logo.pdf
listings-disable-line-numbers: true
footer-left: 'Confidentiality Statement Goes Here'
echo "date: Build Date $(date --iso-8601=date)"


The following folks did the heavy lifting on this effort:

Josh Dotson
David Wang
Hang Xie