Metadata-Version: 2.4
Name: ansible-docsmith
Version: 2.3.0
Summary: DocSmith for Ansible: automating role documentation (using argument_specs.yml)
Keywords: ansible,documentation,yaml,cli,automation
Author: foundata GmbH, Andreas Haerter
Author-email: Andreas Haerter <ah@foundata.com>
License-Expression: GPL-3.0-or-later
License-File: LICENSES/GPL-3.0-or-later.txt
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Topic :: Documentation
Classifier: Topic :: Software Development :: Documentation
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Dist: antsibull-docs-parser>=1.2.0,<2.0.0
Requires-Dist: jinja2>=3.1.6
Requires-Dist: markdown-it-py>=3.0.0
Requires-Dist: rich>=14.1.0
Requires-Dist: ruamel-yaml>=0.18.14
Requires-Dist: typer>=0.16.0
Requires-Dist: typing-extensions>=4.4
Maintainer: Andreas Haerter
Maintainer-email: Andreas Haerter <ah@foundata.com>
Requires-Python: >=3.11
Project-URL: Homepage, https://foundata.com/en/projects/ansible-docsmith/
Project-URL: Documentation, https://foundata.com/en/projects/ansible-docsmith/#doc
Project-URL: Repository, https://foundata.com/en/projects/ansible-docsmith/#source
Project-URL: Issues, https://foundata.com/en/projects/ansible-docsmith/#issues
Project-URL: Changelog, https://foundata.com/en/projects/ansible-docsmith/#changelog
Description-Content-Type: text/markdown

# DocSmith for Ansible

**Automating role documentation (using `argument_specs.yml`)**

DocSmith is a documentation generator. It reads a role's
[`meta/argument_specs.yml`](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html#specification-format)
and produces up‑to‑date variable descriptions for the `README.md` as well as
inline comment blocks for `defaults/main.yml` (or other role entry-point files).
It works with roles in both
[stand‑alone form](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html)
and within
[collections](https://docs.ansible.com/ansible/latest/collections_guide/index.html).


<!-- rumdl-disable MD033 -->
<!-- HTML for consistent rendering across limited platform parsers -->
<div align="center" id="project-readme-header">
<br>
<br>

<img src="https://raw.githubusercontent.com/foundata/ansible-docsmith/refs/tags/v2.3.0/assets/images/logos/ansible-docsmith.svg" alt="Logo: DocSmith for Ansible" height="128" />

<br>
<br>

**⭐ Found this useful? Support open-source and star this project:**

[![GitHub repository](https://img.shields.io/github/stars/foundata/ansible-docsmith.svg)](https://github.com/foundata/ansible-docsmith)

<br>
</div>
<!-- rumdl-enable MD033 -->


## Table of contents<a id="toc"></a>

- [Demo](#demo)
  - [Roles using DocSmith](#demo-roles)
  - [Screenshots](#demo-screenshots)
- [Features](#features)
- [Installation](#installation)
- [Usage](#usage)
  - [Preparations](#usage-preparations)
  - [Generate or update documentation](#usage-generate)
    - [Variables without defaults](#usage-defaults-missing)
  - [Project configuration](#usage-config)
    - [Markdown formatter](#usage-formatter)
  - [Collections](#usage-collections)
  - [Validate `argument_specs.yml` and `/defaults`](#usage-validate)
  - [Exit codes](#usage-exit-codes)
  - [Custom templates](#usage-custom-templates)
- [Licensing, copyright](#licensing-copyright)
  - [Trademarks](#trademarks)
- [Author information](#author-information)


## Demo<a id="demo"></a>

### Roles using DocSmith<a id="demo-roles"></a>

- Ansible role: `foundata.acmesh.run`:
  1. [`README.md` with generated variable documentation](https://github.com/foundata/ansible-collection-acmesh/blob/main/roles/run/README.md#role-variables)
  2. [`defaults/main.yml` entry point with generated YAML comments](https://github.com/foundata/ansible-collection-acmesh/blob/main/roles/run/defaults/main.yml)
  3. [`argument_specs.yml`](https://github.com/foundata/ansible-collection-acmesh/blob/main/roles/run/meta/argument_specs.yml)
     (source of truth)
- Ansible role: `foundata.sshd.run`:
  1. [`README.md` with generated variable documentation](https://github.com/foundata/ansible-collection-sshd/blob/main/roles/run/README.md#role-variables)
  2. [`defaults/main.yml` entry point with generated YAML comments](https://github.com/foundata/ansible-collection-sshd/blob/main/roles/run/defaults/main.yml)
  3. [`argument_specs.yml`](https://github.com/foundata/ansible-collection-sshd/blob/main/roles/run/meta/argument_specs.yml)
     (source of truth)


### Screenshots<a id="demo-screenshots"></a>

<!-- rumdl-disable MD033 -->
<!-- HTML for image dimensions, which Markdown cannot express -->
[<img src="https://raw.githubusercontent.com/foundata/ansible-docsmith/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-cli-01-help.png" alt="Screenshot: DocSmith CLI, help" height="128" />](https://github.com/foundata/ansible-docsmith/blob/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-cli-01-help.png)
&#160;
[<img src="https://raw.githubusercontent.com/foundata/ansible-docsmith/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-cli-sshd-01-validate.png" alt="Screenshot: DocSmith CLI, validate; Results for foundata.sshd.run" height="128" />](https://github.com/foundata/ansible-docsmith/blob/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-cli-sshd-01-validate.png)
&#160;
[<img src="https://raw.githubusercontent.com/foundata/ansible-docsmith/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-cli-sshd-02-generate-dry-run.png" alt="Screenshot: DocSmith CLI, generate dry run; Results for foundata.sshd.run" height="128" />](https://github.com/foundata/ansible-docsmith/blob/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-cli-sshd-02-generate-dry-run.png)
&#160;
[<img src="https://raw.githubusercontent.com/foundata/ansible-docsmith/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-cli-sshd-03-generate.png" alt="Screenshot: DocSmith CLI, generate; Results for foundata.sshd.run" height="128" />](https://github.com/foundata/ansible-docsmith/blob/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-cli-sshd-03-generate.png)
&#160;
[<img src="https://raw.githubusercontent.com/foundata/ansible-docsmith/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-readme-sshd-01-toc.png" alt="Screenshot: Part of a README.md ToC, generated with DocSmith" height="128" />](https://github.com/foundata/ansible-docsmith/blob/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-readme-sshd-01-toc.png)
&#160;
[<img src="https://raw.githubusercontent.com/foundata/ansible-docsmith/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-readme-sshd-02-main.png" alt="Screenshot: Part of a README.md's main content describing role variables, generated with DocSmith" height="128" />](https://github.com/foundata/ansible-docsmith/blob/refs/tags/v2.3.0/assets/images/screenshots/ansible-docsmith-readme-sshd-02-main.png)
<!-- rumdl-enable MD033 -->


## Features<a id="features"></a>

- Uses the `argument_specs.yml` from
  [Ansible's built-in role argument validation](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html#role-argument-validation)
  as the source for documentation in READMEs and entry-point files.
- Checks argument specs for structural errors and inconsistencies with
  entry-point `defaults/`. See [validation](#usage-validate) for checks and
  severity levels.
- Provides read-only checks and [exit codes](#usage-exit-codes) for CI/CD
  pipelines and pre-commit hooks.
- Supports Markdown and reStructuredText.
- Converts
  [Ansible markup](https://docs.ansible.com/projects/ansible/latest/dev_guide/ansible_markup.html),
  such as `C(...)`, `O(...)`, `V(...)` and `M(...)`, in descriptions to the
  target format.


## Installation<a id="installation"></a>

[![PyPI package version](https://img.shields.io/pypi/v/ansible-docsmith.svg?logo=pypi)](https://pypi.org/project/ansible-docsmith)

DocSmith needs Python ≥ v3.11. It is available on
[PyPI](https://pypi.org/project/ansible-docsmith/) and can be installed with the
package manager of your choice.

**Using [`uv`](https://docs.astral.sh/uv/getting-started/installation/)
(recommended):**

```bash
uv tool install ansible-docsmith
```

Alternatively, choose one of the following commands:

```bash
pip install ansible-docsmith
```

```bash
pipx install ansible-docsmith
```

The minimum Python version is 3.11 (rather than the newer 3.12 baseline used for
most of our projects) so DocSmith runs on
[Debian 12 "Bookworm"](https://packages.debian.org/bookworm/python3).


## Usage<a id="usage"></a>

### Preparations<a id="usage-preparations"></a>

1. Create `meta/argument_specs.yml` for
   [Ansible's role argument validation](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html#role-argument-validation)
   if it does not exist. Add `description:` to your variables to make the
   generated documentation useful. A complete specification also improves
   argument validation.
2. Add the mandatory `MAIN` markers to your role's existing `README.md` where
   the variable descriptions should appear. Each `ansible-docsmith generate` run
   replaces all content between them:

   ```markdown
   <!-- ANSIBLE DOCSMITH MAIN START -->
   <!-- ANSIBLE DOCSMITH MAIN END -->
   ```

   Optionally, add `TOC` markers inside a hand-written table of contents (ToC).
   These generate list entries for only the DocSmith-managed variable
   documentation:

   ```markdown
   <!-- ANSIBLE DOCSMITH TOC START -->
   <!-- ANSIBLE DOCSMITH TOC END -->
   ```

   Alternatively, add `TOC-FULL` markers to generate a complete ToC of all
   README headings, including hand-written ones:

   ```markdown
   <!-- ANSIBLE DOCSMITH TOC-FULL START -->
   <!-- ANSIBLE DOCSMITH TOC-FULL END -->
   ```

   Headings with an explicit anchor (like `## Usage<a id="usage"></a>`) are
   linked exactly; for other headings, the anchor is derived from the heading
   text and `validate` emits a notice, as the derivation cannot be guaranteed to
   match your rendering platform for exotic titles.

The entry-point variable files in your role's `defaults/` directory need no
additional preparation. DocSmith adds or replaces formatted inline comment
blocks above the variables defined there.

**The marker contract** in short:

- **All content between a START and END marker pair is owned by DocSmith** and
  gets replaced on every `generate` run. Outside content is preserved unless you
  enable a [whole-file Markdown formatter](#usage-formatter).
- **A lone marker is always an error**, no matter the type: a `START` without
  its `END` (or vice versa) fails validation instead of guessing where the
  managed section ends. This applies to `MAIN`, `TOC`, `TOC-FULL` and the
  role-named markers in collection READMEs alike.
- **A missing README is fine**: `generate` creates one from a basic skeleton,
  markers included. However, an *existing* README **without** the mandatory
  `MAIN` markers is a hard validation error, so DocSmith cannot accidentally
  overwrite hand-written content in a README that was never prepared for it.

Example files:

- Markdown:
  [`README.md`](https://github.com/foundata/ansible-docsmith/blob/refs/tags/v2.3.0/tests/fixtures/example-role-simple-toc/README.md?plain=1)
- reStructuredText:
  [`README.rst`](https://github.com/foundata/ansible-docsmith/blob/refs/tags/v2.3.0/tests/fixtures/example-role-simple-toc-rst/README.rst?plain=1)
  (difference to Markdown: `..` comments, `.. contents:: **Table of Contents**`
  directive)


### Generate or update documentation<a id="usage-generate"></a>

The path defaults to the current directory. Project settings are discovered
automatically; explicit CLI options override them.

```bash
# Safely preview changes without writing to files. No modifications are made.
ansible-docsmith generate /path/to/role --dry-run

# Check whether the documentation is up to date without writing files:
# exit code 1 (and a diff) if a run would change anything, 0 otherwise.
# Useful for CI/CD pipelines and pre-commit hooks.
ansible-docsmith generate /path/to/role --check

# Generate / update README.md and comments in entry-point files (like defaults/main.yml)
ansible-docsmith generate /path/to/role

# Show help
ansible-docsmith --help
ansible-docsmith generate --help
```

Advanced parameters:

```bash
# Generate / update only the README.md, skip comments for variables in
# entry-point files (like defaults/main.yml).
ansible-docsmith generate /path/to/role --no-defaults

# Generate / update only the comments in entry-point files (like defaults/main.yml),
# skip README.md
ansible-docsmith generate /path/to/role --no-readme

# Do not document nested options ("dict attributes") in the comments of
# entry-point files (like defaults/main.yml)
ansible-docsmith generate /path/to/role --no-defaults-comments-nested

# Verbose output for debugging
ansible-docsmith generate /path/to/role --verbose
```


#### Variables without defaults<a id="usage-defaults-missing"></a>

Use `generate --defaults-include-missing` to append an owned comment section for
required and optional top-level variables absent from the entry-point defaults
mapping and without an explicit specification `default:`. Nested options stay
under their parent; example values are not invented.

```yaml
# ANSIBLE DOCSMITH MISSING START
#
# The following variables have no default values. They are documented
# here as comments for easier discovery:
#
# Server hostname.
#
# - Type: str
# - Required: Yes
# app_host:
#
# ANSIBLE DOCSMITH MISSING END
```

The option is off by default. Empty and comment-only files are supported.
Missing `defaults/<entry-point>.yml` files and their directory are created only
when there are eligible variables; existing `.yaml` files are reused. An
explicit specification `default: null` is still a default, not a placeholder.

DocSmith regenerates this section in specification order. Removing a variable
from the spec or assigning it outside the markers removes its placeholder.
Keep assignments outside the section: malformed markers or active YAML inside
it stop generation before any files are written.

`--no-defaults-include-missing` removes the owned section on the next
generation, retaining the file. `--no-defaults` leaves defaults files entirely
untouched. Set `defaults_include_missing = true` under `[generate]` to enable
the feature through project configuration. It also applies to every role in a
collection.


### Project configuration<a id="usage-config"></a>

Use `ansible-docsmith.toml` or `.ansible-docsmith.toml` in the selected role or
collection directory. Exactly one file is loaded: having both is an error.
`--config PATH` selects an alternative file, relative to the caller's directory,
and bypasses discovery. `--no-config` skips configuration entirely; it cannot be
combined with `--config`.

There is no inheritance, ancestor search, user configuration or `pyproject.toml`
support. A collection uses its root settings for every role, ignoring role-local
files. When invoking a role directly, use `--config` to reuse the collection's
configuration. CLI options take precedence over file settings, then built-in
defaults. Unknown keys, invalid values and malformed files fail with exit 2,
including when the formatter is disabled.

All behavior settings are shown below with their built-in defaults. Settings for
`generate` and `validate` are independent; `format` and `verbose` apply to both.

```toml
format = "auto"
verbose = false

[generate]
readme = true
defaults = true
defaults_comments_nested = true
defaults_include_missing = false
readme_toc_list_bulletpoints = "auto"
dry_run = false
check = false
markdown_formatter = true
# template_readme = "templates/readme.md.j2"

[validate]
readme = true
argument_specs = true
strict = false
```

`format` accepts `auto`, `markdown` or `rst`; TOC bullets accept `auto`, `*` or
`-`. Template paths in TOML are relative to that config file;
`--template-readme` paths are relative to the caller's directory.

Positive/negative CLI options override configured booleans, including
`--no-check`, `--no-dry-run`, `--no-strict` and `--no-verbose`. Check always
implies dry-run.

```sh
ansible-docsmith generate
ansible-docsmith generate --dry-run
ansible-docsmith generate --check
ansible-docsmith validate
ansible-docsmith generate --config ./alternative.toml
```


#### Markdown formatter<a id="usage-formatter"></a>

Formatting is off unless `[markdown_formatter]` declares a command. DocSmith
formats the **whole merged README**, including hand-written content, before
comparing or writing. Generate, check and dry-run use the same result; the
original file is never formatted merely to make a comparison pass. YAML defaults
and reStructuredText files never enter this hook.

For [rumdl](https://rumdl.dev/), put a reviewed `.rumdl.toml` beside your
DocSmith configuration:

```toml
[markdown_formatter]
command = [
  "rumdl", "fmt", "--config", "{config_dir}/.rumdl.toml",
  "--deny-config-warnings", "--no-cache", "--stderr",
  "--stdin-filename", "{readme}", "-",
]
mode = "stdin"
timeout_seconds = 30
```

The hook is formatter-independent. For example, an installed
[Prettier](https://prettier.io/) can use:

```toml
[markdown_formatter]
command = [
  "prettier", "--config", "{config_dir}/.prettierrc.json",
  "--no-editorconfig", "--parser", "markdown",
  "--stdin-filepath", "{readme}",
]
```

Keep Prettier's `embeddedLanguageFormatting` set to `off` to avoid formatting
embedded code. Install and pin your chosen formatter separately; DocSmith does
not install it.

The command is an argument array, not a shell string. There is no shell
expansion or implicit project executable lookup. Bare executables use `PATH`;
execution uses the README's parent directory as the working directory.
Placeholders are:

|  Placeholder   | Value |
| -------------- | ----- |
| `{readme}`     | Absolute intended README path, for filename context only; never an output argument |
| `{config_dir}` | Absolute directory of the selected DocSmith configuration |
| `{path}`       | Disposable `README.md` outside the project, available only in file mode |

Use `{{` and `}}` for literal braces. Other placeholders, conversions and format
specifications are rejected.

- `mode = "stdin"` (default): the candidate goes to stdin; UTF-8 stdout is the
  formatted document. Diagnostics belong on stderr.
- `mode = "file"`: the command must reference `{path}` and edit that temporary
  file. Stdin is closed; stdout/stderr are diagnostics. For rumdl, use the
  command above without `--stderr --stdin-filename {readme} -`, adding `{path}`
  instead. Name formatter configuration explicitly because the temporary file
  is outside the project.

`timeout_seconds` defaults to 30 and must be positive and finite. Exit 0 is
required; wrapper scripts must wait for their children. Missing commands,
timeouts, nonzero exits, empty/invalid output or
changed markers, headings or explicit anchors fail generation. Formatters must
be deterministic and preserve DocSmith structure; verify that generate,
standalone formatting and check agree after changing tool versions or policy.

**Trust:** discovered commands run with your permissions and environment,
including during `--check` and `--dry-run`. This is not a sandbox, so review
repository configuration, formatter plugins and scripts before running them.
`--no-markdown-formatter` suppresses the hook; `--no-readme` excludes it
entirely. Loading configuration, `validate`, help and version never execute it.


### Collections<a id="usage-collections"></a>

`generate` and `validate` also accept a **collection** path. All roles found via
`roles/*/meta/argument_specs.yml` are then processed like single roles.
Additionally, DocSmith maintains role-named marker sections in the collection's
`README.md` (or `README.rst`), so the collection README can reference the role
documentation without manual upkeep:

```markdown
### My role: foo

<!-- ANSIBLE DOCSMITH TOC foo START -->
<!-- ANSIBLE DOCSMITH TOC foo END -->

### My role: bar

<!-- ANSIBLE DOCSMITH TOC-FULL bar START -->
<!-- ANSIBLE DOCSMITH TOC-FULL bar END -->

<!-- ANSIBLE DOCSMITH MAIN bar START -->
<!-- ANSIBLE DOCSMITH MAIN bar END -->
```

- `TOC <role>` lists the role's variable documentation, `TOC-FULL <role>` lists
  *all* headings of the role's README. Both link into `roles/<role>/README.*`
  using relative paths.
- `MAIN <role>` embeds the role's complete variable documentation directly in
  the collection README. All anchors get a `<role>-` prefix so several embedded
  roles cannot collide on variable names. If a `TOC <role>` section exists in
  the same (Markdown) document, it links to the embedded documentation instead
  of the role's README.
- Role-named sections are opt-in per role: roles without markers are simply not
  referenced in the collection README (`validate` emits a notice listing them).
  Markers referencing an unknown role produce a warning.

If a formatter is configured, it runs once per Markdown role README and once for
the collection README after all its sections are merged. READMEs without
complete markers are not formatted.

```bash
ansible-docsmith generate /path/to/collection
ansible-docsmith validate /path/to/collection
ansible-docsmith generate /path/to/collection --check
```


### Validate `argument_specs.yml` and `/defaults`<a id="usage-validate"></a>

Validate the argument specifications and their consistency with role entry-point
files in `defaults/`:

```bash
ansible-docsmith validate /path/to/role
```

Checks include:

- Errors for variables present in `defaults/` but missing from
  `argument_specs.yml`, or variables with a `default:` in the specification but
  missing from the entry-point files.
- Warnings for unknown keys in `argument_specs.yml` and invalid Ansible markup
  in descriptions, such as `M()` without a fully qualified collection name
  (FQCN).
- Warnings for required top-level variables assigned in the corresponding
  defaults file, including null values. A role default may satisfy Ansible's
  required check without caller input.
- Notices for non-required variables listed in the specification but absent from
  an otherwise populated entry-point defaults file, and names suggesting secrets
  (such as `*_password` or `*_token`) without `no_log: true`.

Use `--strict` to make warnings fail validation with exit code `1`, for example
in CI/CD pipelines or pre-commit hooks. Notices do not fail validation.

```bash
ansible-docsmith validate /path/to/role --strict
```

To validate selected parts of a role:

```bash
# Skip the README checks (markers and ToC). Useful when only maintaining
# comments in entry-point files.
ansible-docsmith validate /path/to/role --no-readme
# Skip the argument_specs.yml checks (consistency, unknown keys, ...).
# The file must still be parseable YAML.
ansible-docsmith validate /path/to/role --no-argument-specs

# Show help
ansible-docsmith --help
ansible-docsmith validate --help

# Verbose output for debugging
ansible-docsmith validate /path/to/role --verbose
```


### Exit codes<a id="usage-exit-codes"></a>

All commands use conventional exit codes, so DocSmith can be wired into scripts,
CI/CD pipelines and pre-commit hooks without output parsing:

| Exit code | Meaning |
| --------- | ------- |
| `0`       | Success. Warnings and notices alone do *not* fail a run (unless `--strict` is used). `generate --check` returns `0` when the documentation is up to date. |
| `1`       | Validation or processing error (like missing `MAIN` markers, inconsistencies between `argument_specs.yml` and `defaults/`). Also: warnings when `validate --strict` is used, and pending changes when `generate --check` is used. |
| `2`       | Command line or configuration error (unknown option/key, non-existing path, malformed TOML or ambiguous discovery). |

Notices are informational and never affect the exit code. A typical gate:

```bash
ansible-docsmith validate /path/to/role --strict && \
    ansible-docsmith generate /path/to/role --check
```


### Custom templates<a id="usage-custom-templates"></a>

You can customize the generated output by providing your own
[Jinja2 template](https://jinja.palletsprojects.com/en/stable/templates/). The
rendered content will be inserted between the `ANSIBLE DOCSMITH MAIN START` and
`END` markers in the role's README. Name the file `*.md.j2` for Markdown or
`*.rst.j2` for reStructuredText, matching the README format of the role.

```bash
# Use a custom template for README generation
ansible-docsmith generate /path/to/role --template-readme /path/to/custom-template.md.j2

# Combined with other options
ansible-docsmith generate /path/to/role --template-readme ./templates/my-readme.md.j2 --dry-run
```

Template files must use the `.j2` extension (for example, `simple-readme.md.j2`)
and follow Jinja2 syntax. This Markdown example documents top-level options from
every entry point. It uses the built-in anchor convention so generated ToC
entries and option links can resolve:

```jinja
{% set multiple_entry_points = specs | length > 1 %}
{% for entry_point, entry_spec in specs.items() %}
{% set short_anchors = (not multiple_entry_points) or entry_point == "main" %}
{% set prefix = anchor_ns ~ ("" if short_anchors else entry_point ~ "-") %}
## Role variables: `{{ entry_point }}`<a id="{{ prefix }}variables"></a>

{% if entry_spec.options %}
{% for var_name, var_spec in entry_spec.options.items() %}
### `{{ var_name }}`<a id="{{ prefix }}variable-{{ var_name }}"></a>

Type: `{{ var_spec.type }}`

{{ var_spec.description | format_description }}

{% endfor %}
{% else %}
This entry point has no configurable variables.
{% endif %}
{% endfor %}
```

Copy the built-in
[`readme/default.md.j2`](https://github.com/foundata/ansible-docsmith/blob/refs/tags/v2.3.0/src/ansible_docsmith/templates/readme/default.md.j2)
template for a starting point that also includes nested options, defaults and
other option metadata, with conditional sections.

**Available template variables** (the context contract):

|       Variable        |    Type     | Description |
| --------------------- | ----------- | ----------- |
| `specs`               | `dict`      | All entry points in spec file order: entry point name → normalized spec. This is the recommended way to render complete documentation (the built-in templates iterate it). |
| `role_name`           | `str`       | Name of the Ansible role (directory name). |
| `role_path`           | `Path`      | Path to the role directory. |
| `entry_points`        | `list[str]` | All entry-point names, in spec file order. |
| `anchor_ns`           | `str`       | Anchor namespace to prepend to every anchor and internal link the template generates. Empty for role READMEs; `<role>-` when the content is embedded into a collection README via `MAIN <role>` markers. Use it like the built-in templates do, or embedded content of several roles may collide. |
| `primary_entry_point` | `str`       | *Backwards compatibility:* name of the first entry point. |
| `primary_spec`        | `dict`      | *Backwards compatibility:* spec of the first entry point (keys: `short_description`, `description`, `author`, `version_added`, `options`). |
| `options`             | `dict`      | *Backwards compatibility:* variables of the first entry point only. |
| `has_options`         | `bool`      | *Backwards compatibility:* whether the first entry point defines variables. |

Each entry in an `options` dictionary maps a variable name to its normalized
specification with the keys `type`, `required`, `default`, `description`,
`choices`, `elements`, `options` (nested sub-options, same structure),
`version_added`, `no_log` and `aliases`.

**Available Jinja2 filters** (signatures show the optional arguments):

|                                              Filter                                              | Description |
| ------------------------------------------------------------------------------------------------ | ----------- |
| `format_description(value)`                                                                      | Formats a description (string or list of paragraphs) for regular display, including [Ansible markup](https://docs.ansible.com/projects/ansible/latest/dev_guide/ansible_markup.html) conversion. |
| `format_table_description(value, variable_name=None, max_length=250, anchor_prefix="variable-")` | Formats a description for a table cell: markup conversion, HTML stripping, single-line folding and truncation with a `[…]` link to `#<anchor_prefix><variable_name>`. Set `max_length=0` to disable truncation. |
| `format_default(value, table=False)`                                                             | Formats a default value as inline code (`N/A` for `None`). Pass `true` inside Markdown table cells so pipes get escaped. |
| `code_escape(value, table=False)`                                                                | Renders a value as inline code, handling backticks correctly. Pass `true` inside Markdown table cells. |
| `ansible_escape(value)`                                                                          | Escapes Ansible Jinja2 syntax (`{{ }}`) so it renders literally (Markdown only). |
| `csv_escape(value)`                                                                              | Escapes double quotes for `csv-table` cells (reStructuredText templates only). |

**Stability:** the variables and filters documented above are the supported
contract and only change with a major release (deprecated values like `options`
may then disappear). Anything else you might discover by reading DocSmith's
internals, including undocumented context values, filter internals and module
layout, can change in any release.

Templates can also generate playbook examples and author information between the
markers. The following example uses the compatibility context to document only
the first entry point as a task snippet for a playbook. It renders
JSON-compatible defaults with Jinja2's `tojson` filter, whose output is also
valid YAML, and leaves variables without a non-null default commented out.
Supply values for required variables before running the example:

````jinja
## Example playbook

```yaml
- ansible.builtin.include_role:
    name: "{{ role_name }}"
    tasks_from: "{{ primary_entry_point }}"
    defaults_from: "{{ primary_entry_point }}"
{% if options.values() | rejectattr('default', 'none') | list %}
  vars:
{% endif %}
{% for var_name, var_spec in options.items() %}
{% if var_spec.default is not none %}
    {{ var_name }}: {{ var_spec.default | tojson }}
{% else %}
    # {{ var_name }}: # {{ var_spec.description | format_description | replace('\n', ' ') }}
{% endif %}
{% endfor %}
```

## Author information

{% if primary_spec.author %}
{% for author in primary_spec.author %}

- {{ author }}
{% endfor %}
{% endif %}
````


## Licensing, copyright<a id="licensing-copyright"></a>

<!--REUSE-IgnoreStart-->
<!-- rumdl-disable MD034 --><!-- should match SPDX-PackageSupplier -->
Copyright (c) 2025, 2026, [foundata GmbH](https://foundata.com/)
(https://foundata.com)
<!-- rumdl-enable MD034 -->

This project is licensed under the GNU General Public License v3.0 or later
(SPDX-License-Identifier: `GPL-3.0-or-later`), see
[`LICENSES/GPL-3.0-or-later.txt`](https://github.com/foundata/ansible-docsmith/blob/refs/tags/v2.3.0/LICENSES/GPL-3.0-or-later.txt) for the full
text.

The [`REUSE.toml`](https://github.com/foundata/ansible-docsmith/blob/refs/tags/v2.3.0/REUSE.toml) file provides detailed licensing and copyright
information in a human- and machine-readable format. This includes parts that
may be subject to different licensing or usage terms, such as third-party
components. The repository conforms to the
[REUSE specification](https://reuse.software/spec/). You can use
[`reuse spdx`](https://reuse.readthedocs.io/en/latest/readme.html#cli) to create
a
[SPDX software bill of materials (SBOM)](https://en.wikipedia.org/wiki/Software_Package_Data_Exchange).
<!--REUSE-IgnoreEnd-->

[![REUSE status](https://api.reuse.software/badge/github.com/foundata/ansible-docsmith)](https://api.reuse.software/info/github.com/foundata/ansible-docsmith)


### Trademarks<a id="trademarks"></a>

Third-party trademarks used in this repository:

- Ansible®, Fedora® and Red Hat® are trademarks of Red Hat, Inc., registered in
  the United States and other countries.
- Debian® is a trademark of Software in the Public Interest, Inc., registered in
  Germany and the United States.
- Ubuntu® is a trademark of Canonical Ltd., registered in Germany, the European
  Union and the United States.

Their use here is purely descriptive and does not imply any affiliation with or
endorsement by the trademark holders.

Own and licensed trademarks used in this repository:

- foundata® is a trademark of [IPAM GmbH](https://ipam-services.com/),
  registered in Germany and the European Union, licensed to
  [foundata GmbH](https://foundata.com/).


## Author information<a id="author-information"></a>

This [project](https://foundata.com/en/projects/) was created and is maintained
by [foundata](https://foundata.com/). If you like it, you might
[buy us a coffee](https://buy-me-a.coffee/ansible-docsmith/).

The Ansible DocSmith project is *not* associated with
[Red Hat](https://www.redhat.com/) nor the
[Ansible project](https://ansible.com/).
