docsmith is a GitHub template for Go CLIs whose documentation should build
itself. Four small generators under internal/tools/ turn what is already in
the repository into the parts of a README that usually go stale: a themed
banner, architecture diagrams, a command reference read from the real
--help output, and terminal screenshots of examples that CI runs on every
push. One file, docsmith.toml, drives all of them, so there is no
project-specific code to edit.
| Generator | Reads | Writes |
|---|---|---|
genbanner |
[banner] in docsmith.toml |
banner-dark.svg, banner-light.svg |
gendocs |
<binary> --help, recursively; Go package doc comments |
the CLI reference and the project tree, between gendocs:cli and gendocs:layout markers |
genexamples |
testdata/examples/*.txtar |
terminal SVGs rendered with freeze, between gendocs:example:ID markers |
gendiagram |
docs/diagrams/*.toml |
NAME-dark.svg, NAME-light.svg |
Every SVG comes in a dark and a light variant, and the README picks one with
<picture> and prefers-color-scheme, so it matches the reader's GitHub
theme.
The examples are the part that keeps the docs honest. Each .txtar file is
a testscript
that runs the real binary and asserts on its output, plus a display.sh
section that shows the same commands in the docs. go test runs the script;
genexamples renders the display. This one runs in CI with the rest of the
tests:
-
Click Use this template on GitHub, or run
gh repo create my-cli --template viniciusdc/docsmith --clone. -
Rename the module in
go.modand its imports:go mod edit -module github.com/you/my-cli, then replacegithub.com/viniciusdc/docsmithincmd/. -
Replace
cmd/helloandinternal/textstatwith your CLI. Any cobra binary works. -
Edit
docsmith.toml: project name, tagline,binary,main, the banner text, colours and motif, and the layout annotations. -
Replace
testdata/examples/*.txtarwith examples of your commands, anddocs/diagrams/how-it-works.tomlwith your own diagram. -
Install the tools and regenerate everything:
make tools # freeze and golangci-lint make generate # banner, diagrams, CLI reference, layout, examples
-
Commit the generated files, SVGs included.
The generators do not depend on anything else in this repository, so they can be dropped into an existing Go module:
-
Copy
internal/tools/genbanner,gendiagram,gendocsandgenexamples, plusdocsmith.tomlat the root of the module. -
Add the dependencies they import:
go get github.com/BurntSushi/toml github.com/rogpeppe/go-internal/testscript
-
Set
[project].binaryand[project].mainindocsmith.toml, and point[docs].cli_fileand[docs].layout_fileat the Markdown files that should receive the generated sections. Leave either empty to skip it. -
Add the markers where generated content belongs. Each marker sits on a line of its own; markers inside code blocks, like these, are ignored:
<!-- gendocs:cli --> <!-- /gendocs:cli --> <!-- gendocs:layout --> <!-- /gendocs:layout --> <!-- gendocs:example:my-example --> <!-- /gendocs:example:my-example -->
-
Copy
cmd/hello/script_test.gonext to yourmainpackage (adjust the binary name and the relative path to the examples directory) so the.txtarexamples run undergo test. -
Merge the
docs,banner,diagrams,examples,examples-checkandgeneratetargets from theMakefile, and copy.github/workflows/drift.yml.
Required tools: Go, and for rendered examples
go install github.com/charmbracelet/freeze@latest. Without freeze,
genexamples writes a fenced code block instead of an image.
An example is a .txtar file whose comment area holds # doc: headers and
a testscript, followed by the files the script needs and a display.sh:
# doc:id greet-and-count marker name and SVG file name
# doc:file README.md the file that holds the markers
# doc:tested true adds "✓ CI tested" to the footer
exec hello greet Ada --greeting Hi
stdout '^Hi, Ada!$'
-- display.sh --
$ hello greet Ada --greeting Hi
Hi, Ada!
display.sh is a terminal session: lines starting with $ are commands,
drawn bright, and everything else is output, drawn muted and verbatim. Set
# doc:lang bash (or any language freeze knows) to highlight the snippet as
code instead. Rendered SVGs are committed and carry a hash of the snippet
they show; genexamples re-renders them when the snippet changes, and
genexamples -force re-renders all of them.
A diagram is a TOML file of nodes, edges and optional groups. Nodes are
styled source, stage, sink or planned; edges can carry a label and be
dashed. Without width/height the layout is computed from the edges;
with them, every node gives its own x/y, which is how
how-it-works.toml lines each generator
up with its output.
.github/workflows/drift.yml regenerates the banner, diagrams, CLI reference,
layout and examples on every push and pull request, and fails when the
result differs from what is committed. freeze output can differ between
machines and freeze versions, so CI does not install it. The rendered example
SVGs are checked through the Markdown that embeds them: when an SVG is stale,
CI falls back to a code block, the Markdown changes and the check fails. Fix
it locally with make generate.
Everything lives in docsmith.toml; every key has a default.
| Table | Keys |
|---|---|
[project] |
name, tagline, binary, main |
[banner] |
title, subtitle, output_dir, motif (blocks or lanes), [banner.dark]/[banner.light] with accent and palette, optional [[banner.rows]] or lanes + [[banner.shifts]] |
[diagrams] |
source_dir, output_dir |
[examples] |
dir, svg_dir, width |
[docs] |
cli_file, layout_file, [docs.layout] with root_files, skip, max_depth and [docs.layout.annotations] |
make help # list targets
make test # unit tests and example scripts
make lint # golangci-lint
make generate # banner, diagrams, docs and examples
make examples-check # what the drift workflow runs for examplesThe sample CLI's reference is generated into docs/CLI.md.
Makefile Docs, test and lint targets
cmd/ Executable entry points
hello/ hello is the sample CLI that ships with the docsmith template
docs/ Generated reference docs and their assets
diagrams/ Diagram sources (TOML) for gendiagram
docsmith.toml Configuration for every generator
go.mod Module definition
internal/ Packages private to this module
textstat/ textstat counts the lines, words and bytes in a stream of text
tools/ Documentation generators, run through make
genbanner/ Generates the README banner SVGs from docsmith.toml
gendiagram/ Generates architecture diagram SVGs from TOML definitions
gendocs/ Generates the CLI reference and project layout sections of the docs
genexamples/ Generates executable documentation snippets
docsmith is licensed under the Apache License 2.0. See NOTICE for the fonts embedded in rendered examples.