Documentation is part of the product
The most common reason an automation project dies after the consultants leave is not technical. It is that nobody can find out how it works. The engineer who wrote the roles moves teams. A new hire cannot tell which role configures logging, what the variable app_mode actually does, or whether it is safe to run the patching playbook on a Thursday. They ask in chat, get a half answer, and quietly go back to logging into servers by hand.
Good documentation prevents that. It is also the cheapest way to make a role library outlast its authors, which is why handover documentation is a named deliverable of our Ansible service and not an afterthought.
What good looks like
- Anyone can find, in minutes, whether a role for a task already exists.
- Every variable has a documented type, default and purpose, visible without opening a template.
- Contributing a change is a documented sequence a new engineer can follow on day two.
- Documentation changes with the code, in the same pull request.
- Operational knowledge, such as what to do when a patch run fails, is written down.
How it works in practice
The three core documents
1. Role catalogue. A single page, mostly generated, listing each role with its purpose, supported platforms, owner, version, test status and links. It answers “what do we have?” and shows gaps and duplicates.
2. Variable reference. For each role, a table of variables with type, default, description and whether it is required. This is the page engineers use most. It should never be written by hand.
3. Contribution guide. How to set up a local environment, branch naming, coding standards, how to run lint and tests, how roles are versioned and released, and what a reviewer looks for.
Make the code carry the documentation
The best source for the variable reference is the role’s argument specification, because Ansible also uses it to validate input:
# roles/nginx/meta/argument_specs.yml
argument_specs:
main:
short_description: Install and configure nginx
options:
nginx_worker_connections:
type: int
default: 1024
description: Maximum simultaneous connections per worker process.
nginx_server_names:
type: list
elements: str
required: true
description: Host names the default virtual host answers to.
A short script walks every role, reads these files, and renders Markdown with a Jinja2 template. The same step can pull the role’s description from meta/main.yml and its supported platforms from the galaxy_info section. Because the output is rebuilt in CI on every merge, the reference matches the code at the commit it describes. Where a team already uses collections, the ansible-doc command and tools built on it can render documentation for plugins and modules you write yourself.
Docs as a site
For small teams, Markdown files in a docs/ directory are enough. When you want a searchable site, a static generator such as MkDocs publishes the same files. A minimal workflow regenerates the reference, builds the site and publishes it on merge to main. Diagrams written in Mermaid live in the same Markdown and are reviewed like code.
python scripts/generate_role_docs.py --roles roles/ --out docs/reference/
mkdocs build --strict
The --strict flag makes the build fail on broken links, which is a cheap guard against documentation rot.
Writing the contribution guide
Keep it short enough that people read it. A good one has:
- Prerequisites and a one-command local setup.
- How to create a role from the template, so structure stays uniform.
- The checklist for a pull request: argument spec updated, README entry updated, lint passing, Molecule scenario added or updated, changelog line written.
- Naming rules: role names, variable prefixes, tag names.
- Release process: semantic versioning, tagging, and how consumers update the pin.
Runbooks and decision records
Code explains what, not why or what to do when it breaks. Two additions fill the gap. Runbooks give step-by-step recovery for known situations, such as a failed patch batch or a locked-out SSH user, and are similar in spirit to those described in our Managed DevOps runbooks work. Architecture decision records are one-page notes recording a choice, the alternatives and the reason, such as why you chose AWX over a CI runner or security-only patching over full updates. They stop the same argument being rerun every year.
Decisions and trade-offs
Generated or handwritten. Generate reference material, hand write explanation. Mixing the two in one file leads to arguments about what is safe to overwrite.
Single repository docs or a central site. One site that aggregates every repository is nicer to browse. A docs folder per repository is easier to keep honest. We start with the latter and aggregate when it is worth it.
How much is enough. A three-person team with ten roles needs a README per role and a short guide. A hundred-person organisation with several automation teams needs the catalogue, ownership and a governance process. We scale the effort to the situation, and we say so if the answer is “less than you think”.
When not to write it. Documentation for code that is about to be deleted. Spend the time on the migration instead.
Common failure modes
- Handwritten variable tables. They go stale within a month. Generate them.
- A wiki nobody updates. Move it into the repository and tie it to pull requests.
- Docs for the author, not the reader. Tested by watching a newcomer attempt a task using only the docs.
- No owner for a role. Questions go unanswered. The catalogue lists an owner and a contact.
- Hidden tribal rules. For example, “never run this on Fridays”. Write them as runbook entries.
Delivery and handover
Delivery is a repository folder, a CI job that generates and checks documentation, a published site if wanted, and a working session in which your engineers follow the contribution guide and make a real change. Compliance material, such as the control mapping from the CIS work, is included in the catalogue so that auditors and engineers read the same source.
How to tell it is working
- A new engineer ships a small role change in their first week without asking for help.
- Questions in chat about variables fall, and answers are links to the reference.
- No role merges without documentation, because the pipeline refuses.
- The catalogue shows an owner for every role, and none is more than a release or two out of date.
To see a sample catalogue and variable reference generated from a repository like yours, contact us.