Skip to main content

documator

A documentation CLI. This readme is itself rendered from templates/README.md into the repository root by the documator render command.

Install

uv sync

Usage

documator [--quiet] render INPUT_DIR OUTPUT_DIR [--watch] [--check] [--timeout SECONDS]
documator [--quiet] skills INPUT_DIR OUTPUT_DIR [--watch] [--timeout SECONDS]

render mirrors the input tree.

                                                                                
 Usage: documator render [OPTIONS] {input_dir} {output_dir}                     
                                                                                
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ *    input_dir       <parse>  [required]                                     │
│ *    output_dir      <parse>  [required]                                     │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --watch                                                                      │
│ --check                                                                      │
│ --timeout        SECONDS  [default: root=10.0]                               │
│ --help                    Show this message and exit.                        │
╰──────────────────────────────────────────────────────────────────────────────╯

--check renders the whole tree and writes none of it: nothing is created, overwritten or pruned. Every output that is missing, out of date, or still tracked after its template went away is reported, and the run exits non-zero — so CI can fail on a repository whose generated files have drifted from their templates without the job being able to paper over it. Blocks still run, since their output is what the comparison is about; --check bounds what documator writes, not what a template's commands do. It cannot be combined with --watch.

skills compiles the same templates into the flat <skill-name>/SKILL.md layout Claude's skill loader expects: nesting in the input tree is organisational only, the filename stem becomes the skill name, and the frontmatter is generated — any keys the template declares pass through, and a declared description wins over the name-derived placeholder.

A skill is marked with an @ on its own name: @foo.md, or @bar/ for a folder holding a SKILL.md. Everything unmarked is a term — a note that names something for links to point at and compiles to nothing.

An example tree might look like:

my-templates/
├── @foo.md
├── @bar/
│   └── SKILL.md
├── Tracer bullet.md
├── _hidden.md

and would result in:

.skills/
├── foo/
│   └── SKILL.md
├── bar/
│   └── SKILL.md
                                                                                
 Usage: documator skills [OPTIONS] {input_dir} {output_dir}                     
                                                                                
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ *    input_dir       <parse>  [required]                                     │
│ *    output_dir      <parse>  [required]                                     │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --watch                                                                      │
│ --timeout        SECONDS  [default: root=10.0]                               │
│ --help                    Show this message and exit.                        │
╰──────────────────────────────────────────────────────────────────────────────╯

Notes

_ means the same thing on a heading as it does on a path segment: this is scratch, and it emits nothing. A ## _Notes section — or ## _Improvements, or whatever you want to call it — is somewhere to collect thoughts beside the work they are about, and it is dropped from the output along with every subsection under it. Both commands drop it, from a SKILL.md, a mirrored note and a bundled reference alike.

It is dropped before links resolve and before any command block runs, so a [[dangling link]] there cannot fail the run and a command there never executes. That is what makes the section a safe place to be sloppy — and the reason not to park a link you are relying on in one, because the rename-everywhere guarantee does not reach into it.

Embedding a whole note leaves its marked sections behind, at any depth, so no embed ever drags someone else's scratch into yours. An embed whose #fragment names a marked section still gets it, because that is an author asking for it by name. A heading you want rendered that happens to start with _ should be a code span, ## `_private`, which does not take the mark.

Links

A plain [[wikilink]] is resolved and replaced; only an embed — the same brackets behind a ! — still pulls text in. What it becomes depends on what it points at, so the same link reads correctly in both layouts:

Target Emits
an unmarked note — a term its name: [[Tracer bullet]]Tracer bullet
an @-marked note — a skill an invocation: [[@grill]]/grill
an attachment a path to where it landed: [[diagram.png]][diagram](../assets/diagram.png)

The @ and _ prefixes are input-side vocabulary and never reach the reader. [[Target|display]] sets the wording for a term or an attachment; a skill ignores it, because /grill is a call rather than prose. A #fragment rides along on whatever the link emits.

Renaming a note is therefore a rename everywhere it is mentioned, and a link that resolves to nothing — or to two notes at once — is reported and fails the run with exit 1, leaving the source [[link]] in place so the author can see what they wrote. A link inside a fence or a code span is quoted rather than resolved, which is how this table is written; so is anything a command prints.

Output

Every problem is logged where it arises and again at the end of the run, so a long render does not bury its errors above the scrollback. The run closes with a count — 12 files, 1 warning, 2 errors — followed by the warnings and then the errors, worst news nearest the prompt. Under --watch each recompile closes the same way, since a session has no other end to report at.

Log lines are coloured by level when stderr is a terminal, and plain when it is a pipe or when NO_COLOR is set. --quiet drops the per-file chatter and keeps warnings, errors and the summary; a quiet run that prints nothing is a run that had nothing to report.

Try it

mkdir -p 'docs/guides/@plan/references' out compiled
printf '# Review\n\nRun [[@plan]] against a [[Tracer bullet]] first.\n' > 'docs/guides/@review.md'
printf -- '---\ndescription: Plan a change\n---\n# Plan\n' > 'docs/guides/@plan/SKILL.md'
echo '# Spec' > 'docs/guides/@plan/references/spec.md'
echo 'A thin vertical slice.' > 'docs/Tracer bullet.md'
uv run documator render docs out
uv run documator skills docs compiled

Two layouts over one tree. render mirrors it into out/, so guides/@review.md stays guides/review.md. skills flattens it into compiled/: the bare guides/@review.md becomes review/SKILL.md with a name-derived description, and the guides/@plan/ folder becomes plan/SKILL.md — carrying its declared description through — with references/spec.md bundled beside it as plan/references/spec.md. Tracer bullet.md is a term: render mirrors it like any other note, but it compiles to no skill, and it exists so the link in the review has something to name.

This block is extracted verbatim and run by test_readme.py.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

documator-1.2.0.tar.gz (96.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

documator-1.2.0-py3-none-any.whl (72.6 kB view details)

Uploaded Python 3

File details

Details for the file documator-1.2.0.tar.gz.

File metadata

  • Download URL: documator-1.2.0.tar.gz
  • Upload date:
  • Size: 96.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for documator-1.2.0.tar.gz
Algorithm Hash digest
SHA256 b8f53e0f8abea49ec2668d0e36fadb0b62452e9dffd05ee14b5ac5998a88960e
MD5 28a6064112531de18dc51e9c316a8479
BLAKE2b-256 08cdb605aa8cb46c305e98cf292657260a246ebe26746a58102ec43a6b44dcd1

See more details on using hashes here.

Provenance

The following attestation bundles were made for documator-1.2.0.tar.gz:

Publisher: ci.yml on MartinBernstorff/documator

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file documator-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: documator-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 72.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for documator-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b4d737e6d6864ef5c06167ba745edeab0da0a760ebda28a8ad502a095d1bcce3
MD5 cf2583c6782f5abff731552ace6d8df9
BLAKE2b-256 308e8d4e8f8e94e11b15d2e35b3d429c49f22b826601b034ad6bbae78687a376

See more details on using hashes here.

Provenance

The following attestation bundles were made for documator-1.2.0-py3-none-any.whl:

Publisher: ci.yml on MartinBernstorff/documator

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

1.5.0

2 files

1.4.1

2 files

1.4.0

2 files

1.3.0

2 files

This release

1.2.0 This release

2 files

1.1.0

2 files

1.0.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page