docs-cli
A prescriptive, lightweight CLI (docs) for managing trees of structured markdown documentation.
Treats each Markdown file as a small, self-describing record. A short metadata block under the H1 captures the doc's status, role, and relationships; the docs CLI uses that metadata to derive an index, archive completed work, validate consistency, and answer queries — without forcing you to maintain cross-references by hand.
Why
Documentation directories rot. Hand-maintained INDEX.md files drift from reality. Descriptions get duplicated and lose sync. Plans pile up alongside completed work with no clear lifecycle.
docs makes each file self-describing and treats the index as a derived view. The doc itself is the source of truth; the index is generated.
Convention at a glance
# Title
Lifecycle: active
Role: spec
Project: docs
Updated: 2026-05-23
Related:
- pairs-with: convention.md
- implements: charter.md
## …
- Plain
Label: valuelines under the H1; a bare-label list group (likeRelated:) may follow after a blank line. LifecycleandRolecome from controlled vocabularies (extensible per-project, additive only).Related:is followed by bullets in<verb>: <path>form.- No YAML frontmatter, no parser dependency, readable in any Markdown viewer.
See docs/convention.md for the full spec.
Commands
docs new <role> <slug> [--project NAME] [--body-from PATH|-]
Scaffold a doc with the right metadata; --body-from writes the body atomically.
docs index [DIR] [--exclude PATTERN] Regenerate INDEX.md from metadata in DIR.
docs archive <file> [--reason "…"] [--cascade-only GLOB] [--cascade-dry-run] [--json]
Archive: edit Lifecycle, record Archived:, move to archive/<date>/,
rebase stale body links, refresh index. Related docs need an explicit scope.
docs mv <old> <new> [--dry-run] [--json] Move + rewrite Related: references AND stale body links across the tree.
docs relate add|remove SOURCE VERB TARGET Add or remove a reciprocal relationship pair across both endpoints.
docs list [filters] [--json] [--exclude PATTERN]
Query view of the tree.
docs check [DIR] [--exclude PATTERN] Validate metadata, refs, status/location drift, reciprocal edges,
body links, and archive-date drift.
docs touch <file> [--check] Bump Updated: to today; --check re-validates the tree afterwards.
docs stamp <file> Stamp a metadata block onto a file that was written by hand.
docs project rename <old> <new> Rename a project across the tree.
docs project set <file> <name> Reassign a single doc to another project.
docs migrate <dir> [--apply] [--summary] [--only ambiguous] [--exclude PATTERN]
Adopt a foreign Markdown directory into the convention (dry-run by default).
docs install-skill [--dest DIR] Materialise the bundled agent skill onto this host.
See docs/cli.md for full surface and exit codes.
What 2.0 enforces
The 2.0 train turned four classes of silent documentation rot into hard errors, and stopped the tool from causing two of them itself:
- Reciprocal edges.
precedes/follows,depends-on/required-byandblocks/blocked-bymust point both ways. A one-sided edge is amissing-inverseerror;docs relate add|removewrites or removes both ends in one call. - Body links. Local Markdown links in prose are validated. A destination
that does not exist is
broken-body-link; one that escapes the tree isoutside-root-body-link. - Move-safe rewrites.
docs mvanddocs archiverebase the body-link destinations a move makes stale — not justRelated:references — so an archive or rename no longer leaves a tree that failsdocs check. Both verbs build and validate the whole plan before the first byte moves. - Archive dates.
docs archiverecords anArchived:field on every document it moves, anddocs checkreportsarchive-date-driftwhen a document's recorded date disagrees with the dated directory it sits in.docs mvrefuses a move between two different dated archive directories. - Explicit archive scope. Bare
--cascadeis retired: it refuses and writes nothing. Use--cascade-dry-runto preview, then--cascade-only GLOBto write an explicit scope.
Upgrading a 1.x tree surfaces pre-existing damage as errors on the first
docs check. That is intentional, and the
CHANGELOG's
Upgrading from 1.x section carries the repair recipe for each rule.
Install
pip install docs-cli # lands `docs` on PATH
docs install-skill [--dest DIR] # materialise the bundled agent skill (default: ~/.claude/skills/docs/)
Requires Python 3.11+ (for stdlib tomllib). No third-party runtime dependencies.
Adopting an existing tree
Have a directory of foreign Markdown specs? docs install-skill materialises an agent skill that walks an agent through docs migrate <dir> → triage → docs migrate --apply. See docs/archive/2026-05-25/m8-adoption-workflow.md for the full agent-driveable workflow, the bundled adoption playbook for the procedural deep-dive, or run docs migrate <dir> directly for a dry-run plan.
For development:
git clone https://github.com/ArtRichards/docs-cli.git ~/opt/docs-cli
cd ~/opt/docs-cli
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest -q
Status
Released on PyPI — pip install docs-cli. The on-disk Markdown convention is stable and backward-compatible: 2.0 adds the Archived: field but never rewrites existing files on upgrade, and the only breaking keyword change to date remains the one-time Status: → Lifecycle: rename (no backward-compat alias). What 2.0 breaks is automation, not data — new hard docs check rules and the retired bare --cascade.
For current state, see the canonical sources — kept in sync by the tooling rather than duplicated here:
- CHANGELOG — the current version and full release history.
docs/status.md— development progress.docs/plan.md— the roadmap.
License
MIT — see LICENSE.
Metadata
Release files for docs-cli 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| docs_cli-2.0.0.tar.gz | 1.6 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| docs_cli-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.8 MB
Release files / docs_cli-2.0.0.tar.gz
| Download URL | docs_cli-2.0.0.tar.gz |
|---|---|
| Size | 1.6 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c62f22d35067cb42a8c241e1d36e161f60ac533b33658ab41f804a2a2c862b66
|
|
BLAKE2b-256 checksum How to use checksums |
d9064f0dc6ed8ec3e58129ad89c715a60e7d8ebafbe77f9a5da54cf9d4753a80
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / docs_cli-2.0.0-py3-none-any.whl
| Download URL | docs_cli-2.0.0-py3-none-any.whl |
|---|---|
| Size | 217.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bcd8aa453415dfe66868f22830fce318c7149d6642935d6167d4de9b2cdaab23
|
|
BLAKE2b-256 checksum How to use checksums |
54fde1c831f55f439dcd4a38b1661bac6acb2b2b4c6d2a701894bf3eaa464455
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|