write-docs
Scaffolds, extends, and reconciles a project's `docs/` tree in the TitusKirch docs format — one stack-agnostic convention shared across all repos, ADRs…
Skill by TitusKirch
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/tituskirch-write-docs
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: documents, writing
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Shell scripts
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/write-docs
What's inside
- Skill name
write-docs- Description
- Scaffolds, extends, and reconciles a project's `docs/` tree in the TitusKirch docs format — one stack-agnostic convention shared across all repos, ADRs included (append-only records in `docs/99.adr/`). Routes by state — scaffolds when `docs/` is missing, adds to the right section when it exists, reconciles pages when asked (never rewriting prose). Always previews a plan, writing only after confirmation. Use when the user wants to write, add, scaffold, or update documentation, set up docs/, document a feature, record or supersede an architecture decision, or says things like "write the docs", "add a docs page", "document this", "reconcile the docs", "write an ADR", "record this decision", "Doku schreiben", "docs aktualisieren". Also trigger proactively once a feature has cleared review and final approval — when the work is settled, not when implementation ends — to document the shipped result, and offer an ADR when a decision clearly earns one.
- License
- MIT
- Metadata
- summary: Scaffolds, extends and reconciles a project's docs/ tree — ADRs included — in the TitusKirch docs format.
- Instructions
- 167 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
Agent Skills spec issues
- allowed-tools: must be a space-separated string
Files (11)
- REFERENCE.md
- SKILL.md
- adr-index.md · templates/
- adr.md · templates/
- concept.md · templates/
- docs-index.md · templates/
- guide.md · templates/
- how-to.md · templates/
- reference.md · templates/
- resolve-config.sh · templates/
- section-index.md · templates/
SKILL.md (first lines)
# write-docs
The TitusKirch **docs format** — one opinionated, stack-agnostic convention for a project's `docs/` tree, the same in every repo (including client projects). This skill owns the convention; the page mechanics live in [REFERENCE.md](REFERENCE.md), the skeletons in [`templates/`](templates/). Pages are plain Markdown with `title` + `description` frontmatter and numeric-prefixed paths — a clean tree any file-based docs generator can render, index, and feed to an LLM.
**Portable is the default; a rendered site is an opt-in mode.** A repo that publishes its `docs/` through a rendering theme sets `docs.render` in the config, which flips five page rules and nothing else — the [render mode](REFERENCE.md#render-mode). It is **declared, never detected**, so a repo that has not written the key gets the portable tree above, unchanged.
**Opted out?** If the repo config sets `docs` to `false`, this skill is **disabled** for the repo — **stop immediately** (including the proactive trigger) and tell the user docs are turned off in `.tituskirch-skills.json`. An _absent_ `docs` block is **not** disabled — that falls back to defaults/detection. Check `.docs == false` on the resolved config before any job — and before indexing `.docs.*`. A missing `jq` or config exits non-zero too, so a pass is not evidence the config was read.
## Jobs — pick by repo state + intent
| State / intent | Job |
| :------------------------------------------ | :------------ |
| `docs/` missing | **scaffold** |
| `docs/` exists + "document feature X" | **route/add** |
| "update / align / migrate / reconcile docs" | **reconcile** |
Optional command shortcuts in clients that expose them: `write-docs init`, `write-docs add <topic>`, `write-docs reconcile`. Otherwise infer from state and the request. **Always: plan → confirm → apply.**
**Proactive trigger** — don't wait to be asked. Once a feature has passed all its reviews and reached final approval (signed off or merged), engage this skill yourself and run the **route/add** job for that feature. Trigger on _final approval_, not on _implementation finished_ — code still facing review is too early, and a feature that gets reworked shouldn't be documented twice. The write still follows plan → confirm → apply. An ADR has its own proactive moment, on its own trigger: [when a decision earns one](#when-a-decision-earns-an-adr).
## What belongs in docs at all
**Code says what happens. Docs say why.** An agent reads the code, so a page that narrates what the code does is a slower, staler copy of something already open in the editor — and if the code needs narrating, the fix is the code, not a page about it.
Before writing anything, ask what the reader could **not** recover by reading the source. Exactly three answers survive that test:
| Code cannot express | Because | Goes to |
| :---------------------------- | :------------------------------------------------------------------------------------------- | :---------------------------- |
| **The roads not taken** | What was rejected, and why, leaves no trace in what shipped | `adr`, `concepts` |
| **How new work here is done** | The intended approach for the next change is not a property of the current one | `conventions`, `guides` |
| **Where to start** | A repo has no first line; which seam to enter by, and how the parts relate, is not in a file | `concepts`, `getting-started` |
Everything else — what a function does, which options exist, what a command prints — either belongs in the code and its own reference output, or is [already in a file](#route--add--docs-exists) that owns it. If a planned page fits none of the three rows, that is the answer: don't write it.
## Routing matrix — what you changed → page type → section
| You added / changed | Page type | Section |
| :---------------------------------------------- | :------------------------ | :---------------------------------------- |
| A user-facing capability's usage | guide / tutorial | `guides` |
| A repeatable task / "add a new X" | how-to (ends w/checklist) | `guides` |
| A subsystem, model, or how-it-works | concept / architecture | `concepts` |
| A lookup value: env var, CLI flag, config, API | reference entry | `reference` |
| Setup / install / first-run change | (update existing) | `getting-started` |
| A run / deploy / maintain procedure | how-to or concept | `operations` |
| A project-specific rule or pattern | concept | `conventions` |
| An architectural decision + its reasoning | ADR (own schema) | `adr` |
| An explanatory image or requested terminal demo | media in the owning page | existing section; artifacts in `_assets/` |
A real feature usually spans several types: how-it-works (`concepts`) + usage (`guides`) + lookup values (`reference`). **"How it works" means the shape and the reasoning** — the seams, the invariants, why it is built this way — never a walk through the implementation, which the code states better and keeps current for free.
**The `reference` row is the one to challenge.** Lookup values earn a page only where nothing machine-readable already holds them — an HTTP API with no published schema, env vars with no `.env.example`. Where a schema, a manifest or `--help` is the real answer, the reference page is one sentence naming it plus whatever it cannot say (which values are safe to change, which combinations conflict). A transcribed option table is the single most common stale page in any repo. **Lead with how-it-works and how-to-use; push every lookup value to `reference` and link to it.** Page type is implied by section + template — it is **not** a frontmatter field. Catalogue, core sections and presets: [REFERENCE.md](REFERENCE.md).
**ADRs are the standing exception.** They live in `docs/99.adr/` (fixed prefix, flat), are named `NNNN-title.md` — a permanent decision id plus an imperative verb phrase — carry `status` + `date` on top of the house frontmatter, run `Context` / `Decision` / `Consequences` (Nygard) with an optional `Alternatives considered`, and are **append-only** — a reversed decision writes a new ADR and marks the old one `superseded`, never edits it; a decision that still stands but whose reasoning has been overtaken grows a dated addendum under its own `## Amendments`, the one thing an accepted record may gain in place. A concept page explains how a thing works _today_; an ADR records why it was chosen, _then_. Full contract: [REFERENCE.md](REFERENCE.md#architecture-decision-records).
**Media follows its own [contract](REFERENCE.md#media).** Use `docs/_assets/` for documentation captures, reuse artifacts shared with a README, and prefer Mermaid for diffable diagrams. For a requested terminal capture, optionally call `vhs-demo` with the page, docs context and output path; its absence leaves an explicitly outstanding capture. The writer owns inclusion/layout and the capture skill owns production/verification.
## When a decision earns an ADR
The matrix above says _where_ a decision goes; this says _whether_ there is one to record. Ask it **before** routing — the `adr` row is the only one whose page cannot be pruned later, because the log is append-only.
**The threshold.** A decision earns an ADR when it **constrains work that comes later** and **its reasoning would otherwise be lost**: a choice between real alternatives, a convention every part of the project has to follow, a trade-off that looks like a mistake until the reason is known. Both halves have to hold — a constraint whose reason is obvious from the code needs no record, and a well-argued call that binds nothing later is a comment, not an ADR.
Decisions that typically clear it: architectural shape · integration patterns between parts · technology choices carrying lock-in · boundary and scope decisions · deliberate deviations from the obvious path · constraints invisible in the code · alternatives rejected for non-obvious reasons. A list of the usual suspects, not a checklist — the threshold above is what decides.
**Three signs of a certain ADR** — hard to reverse, surprising without context, the result of a real trade-off. All three together are **sufficient**: write the record, no further argument needed. They are **never necessary** — the cheapest convention in the repo still earns an ADR if it binds later work and its reason would otherwise be lost, and gating on reversal cost alone would exclude exactly the decisions that are easiest to break by accident.
**Size is not the gate, and never a reason to skip one.** _An ADR can be a single paragraph. The value is in recording that a decision was made and why — not in filling out sections._ The required H2s stay, and any of them may be one sentence ([contract](REFERENCE.md#architecture-decision-records)).
**What may go _in_ it is the separate question — and the one append-only makes permanent.** No sentence in an accepted record can be corrected, so every sentence has to still be true years from now. That rules out the state of the world (_currently_, _is being_, a version, a claim about what some tickets hold), anything transcribed out of a file, and any enumeration a later change will extend. `Context` carries the constraint that forced the decision, not an inventory of the project; a consequence that prescribes how future work is done is a convention and belongs in `conventions/`, where it can be edited. Freezing a fact deliberately is fine — write it in the past tense. The full test: [REFERENCE.md](REFERENCE.md#what-the-body-may-hold).
**Offer an ADR proactively** once a decision clearly clears the threshold — same shape as the proactive trigger above: propose the record, plan → confirm → apply, and never write one unasked. _Clearly_ is the bar; a borderline call is the human's to make, so name it and let them answer.
## Scaffold — `docs/` is missing
1. **Resolve the preset** — `docs.preset` config → detect from the repo (bin/CLI → `cli`, a published manifest — library, module, agent/skill set → `package`, a UI app → `app`, a server entrypoint with no frontend build → `service`, IaC → `infra`) → ask. The preset is the **whole** set of sections to scaffold; none is implicit. **Several signals hit at once in most repos** — a CLI that also publishes a library, a module shipping a demo app — so resolve by **how the thing is primarily consumed**, not by what the repo contains: invoked → `cli`, imported into another project → `package`, run and used → `app`/`service`, applied to an environment → `infra`. Genuinely co-equal → ask.
2. **Resolve the language, then the locales** — `docs.language` → root `language` → existing docs/repo language → `en` (see [REFERENCE.md#config](REFERENCE.md#config)). That is also the tree's **default locale**, living at the source root with no folder of its own. `docs.locales` names the **additional** ones, each a folder inside the source (`docs/de-DE/`); absent means single-locale, exactly as before ([Locales](REFERENCE.md#locales)). When set, `docs.instructions` shapes the generated-docs wording (tone, house conventions) — additive only, never overriding the docs format or guardrails.
3. **Resolve the [render mode](REFERENCE.md#render-mode)** — `docs.render`, or portable. **Read the key; never infer it** from a dependency or a config file, and never offer to write it — a repo states its own rendering target, and detection reads the tree that most needs the mode as the one that needs it least. Portable is the answer whenever the key is absent.
4. **Plan the tree** — the preset's sections, plus any its conditional column earns here; show it.
5. **Drop any section that would only redirect.** For each planned section ask: does this repo have a page's worth of material that is **not** already canonical somewhere else — a README that covers install and first run, a committed schema that _is_ the config reference, per-module docs that ship with their module? If not, the section's `index.md` can only say "the real thing is over there", which costs a click and returns nothing. Leave it out, name it in the plan with the reason, and let **route/add** create it later when it has a page of its own. This applies to every section the preset names — a preset is the starting set, not an obligation.
6. **On confirm** — create numeric-prefixed section dirs, each with an `index.md` (frontmatter `title` + `description`, plain-text H1), plus a `docs/index.md` landing page. Generated docs are emoji-free. Skeletons: [`templates/`](templates/), with the [render mode](REFERENCE.md#render-mode)'s flips applied on copy where it is on. **Then, for every locale `docs.locales` lists**, write the same tree translated under `docs/<locale>/` — same paths, same numeric prefixes, same slugs, with only `title`, `description` and body prose in that language.
A scaffold that produces one section is a **success**, not a failure — the tree's job is to hold what has no other home, and in a repo whose parts already document themselves that can be a single section. Numbering starts at `1.` over whatever survives, so nothing looks missing.
## Route / add — `docs/` exists
1. Run the routing matrix; list **every** page to create or touch.
2. New page → next free `N.kebab.md` in the section, frontmatter `title` + `description`, body from the matching template, then link it from that section's `index.md`. **Under the [render mode](REFERENCE.md#render-mode)** the same step drops the body H1, writes an absolute doc path, and leaves the section index to its page-cards component rather than gaining a bullet.
3. **How-tos end with a checklist.** Add a `> [!NOTE]` **Status** callout (see [REFERENCE.md#status-marker](REFERENCE.md#status-marker)) if the feature isn't shipped yet — the [render mode](REFERENCE.md#render-mode) writes that marker as its own callout component instead, because the blockquote form does not render there at all.
4. **Delta principle** — don't restate what something else already documents; link it, and write the project-specific delta plus the glue. Three sources outrank a page here, in descending order of how badly a copy hurts:
- **A file in this repo.** `package.json`'s scripts, a workflow, a schema, a lockfile, a config — a doc that lists their contents is wrong the moment the file changes, and nothing will tell you. Name the file and what is surprising about it; never transcribe values, versions or option tables out of it.
- **Anything the repo ships.** A library, plugin or skill travels without `docs/`, so it must carry its own reference — a second copy here is the one guaranteed to drift.
- **An authoritative upstream source** — framework docs, a dependency's README, a standard.
A strong guideline, not a hard block: cross-cutting glue, and the reason a thing is set the way it is, are exactly what no source file states.
5. **Updating** an existing topic — the one-topic-per-page rule means there's usually exactly one page; `grep docs/` for the term, edit it **in place**, never open a second page on the same topic, and update affected reference tables + cross-links. **Never for an ADR** — a changed decision is a new ADR that supersedes the old one, and the ADR section's `index.md` decision log gets the row in the same change.
6. Verify every fact against current code before writing.
7. **Every listed locale gets the same page change, in the same plan.** A page created or edited in the default tree is written to `docs/<locale>/` at the identical path for each locale `docs.locales` names — the section `index.md` link included. One change, every tree: leaving the translation for later is what puts them out of step, and the [locale contract](REFERENCE.md#locales) is that they never are. Translate alt text/captions and visible Mermaid labels; preserve shared media references or verified localized variants and report missing required captures. Never copy or generate media in a translation sweep. With `docs.locales` absent this step does not exist.
## Reconcile — align existing docs to the convention
Desired-state, idempotent — like a `--fix` linter for the docs tree.
1. Read the **whole** `docs/` tree fresh (it is live state — never cached).
2. **Resolve the [render mode](REFERENCE.md#render-mode) before diffing anything** — it decides which convention the tree is being measured against, and two of the mechanical fixes below are destructive under the wrong one: they would strip the theme's frontmatter fields off the pages that need them and rewrite the mode's absolute doc paths into dangling relative ones.
3. Diff against the convention and group the plan:
- **Auto-fix (mechanical)** — numbering gaps/dupes, missing `index.md`, removed/unknown frontmatter keys, `N.kebab.md` filename normalization, unambiguous broken links.
- **Prompt (value-needing)** — a missing required field (`title`/`description`): derive a candidate from the H1 / first paragraph and confirm.
- **Import (value-needing)** — a **dedicated ADR directory outside `99.adr/`** (`docs/adr/` and near variants): decisions recorded in someone else's format, which every other category misses, so they are missing from the decision log while the log still reads as complete. Measure **each file** against [the threshold](#when-a-decision-earns-an-adr) first — it governs an adopted record exactly as it governs a written one, and this is the last moment it can be asked, because an append-only log cannot be pruned afterwards. What clears it is proposed as **one** operation — move, rename to `NNNN-title.md`, the log's row, the missing frontmatter, the body under the required H2s — applied only on confirmation. A record holding a decision **and** material the expiry test rejects is **split** in that same proposal — the decision into the log, the rest routed as an ordinary page, a fragment belonging on no page dropped once the human says so — and only where the two come apart with no sentence rewritten. What does not clear the bar at all is routed whole or reported and left alone, in the same plan. Detection rule, the threshold gate, the split's rules, the `date` derivation and what is report-only instead: [REFERENCE.md](REFERENCE.md#foreign-adrs--a-decision-log-written-elsewhere).
- **Report only** — a how-to without a checklist, a page that fits no section, suspected duplication of an upstream source **or of a file in the repo**, any secret detected, missing image targets or required capture sources, suspected unused assets and missing required localized captures. Media is never auto-edited; docs-only non-use is not proof of repo-wide orphanhood ([media contract](REFERENCE.md#media)).
4. Show the **plan + diff**; on confirm apply **only structure + frontmatter**. **Never rewrite prose. Only touch files inside `docs/`.** Two exceptions, both scoped: an **imported** ADR, whose body is **re-homed** under the required H2s — a split sends part of it to a page, and a named fragment is dropped on explicit confirmation, so the author's sentences are moved or removed, never rewritten; and a **locale tree**, which is regenerated rather than reconciled.
5. **Regenerate every listed locale from the default tree.** Where `docs.locales` names a locale, the sweep rewrites `docs/<locale>/` — structure derived from the source, `title`, `description` and body prose translated. This is the one place a reconcile **writes prose**, and it is scoped to the locale trees: the default-locale tree keeps _prose untouched_ in full. For translated pages inside a locale root structural drift is **never** categorized or reported — it means the sweep had not run ([the rules](REFERENCE.md#locale-trees-are-regenerated-not-categorized)). Translate alt text/captions and visible Mermaid labels; preserve shared media references or verified localized variants and report missing required captures. Never copy or generate media in a translation sweep. With `docs.locales` absent this step does not exist.
`99.adr/` is **exempt** — links and the decision log only. An ADR id is permanent, so never renumber one, never rename it to the dot-schema, never close a gap in the sequence ([REFERENCE.md](REFERENCE.md#reconcile-rules)). A **foreign** ADR is outside that exemption: it was never accepted _in this log_, so giving it an id is a first assignment rather than a renumbering, and shaping it on entry is not an edit to an accepted record. A **translated** ADR is outside it too, in the other direction: the record is the source file, its translation is a rendering of one, so a locale tree's `99.adr/` is regenerated with the rest of that tree — ids, filenames and `status` copied across untouched.
<skills-plan>
## Presenting the plan
Everything this skill puts in front of a human — plan, preview, candidate list, findings report —
is read **once, in a terminal**, and answered there. So **every section of it renders on arrival**,From TitusKirch/skills, MIT.
More from TitusKirch/skills
- 0.594score
vhs-demo
TitusKirch
Creates and maintains a scripted, reproducible terminal-demo GIF for a CLI repo from a Charm VHS tape rendered headless via Docker — the .tape is the…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
write-contributing
TitusKirch
Writes and maintains a repo's `CONTRIBUTING.md` in the house style — scaffolds one where none exists, reconciles an existing guide against the repo it…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
decide
TitusKirch
Closes the open decisions a run has already named by putting each one in front of the human as a select dialog — concrete options with the recommendation…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
compact-readme
TitusKirch
Compacts an existing, overstuffed README so the landing view reaches the install/run command in ~30 seconds without losing any information — detail moves into…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
write-readme
TitusKirch
Generates project READMEs in the kirchDev house style — centered hero header with emoji + bold tagline, a one-liner code-snippet hook, feature bullets with…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
tituskirch-skills-config
TitusKirch
Creates, reconciles, and drift-checks `.tituskirch-skills.json` — the committed, repo-root config the other TitusKirch skills read to pick forges, trackers…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
validate-skills
TitusKirch
Validates agent skills against the Agent Skills specification — one named skill, or every skill in a repo — and reports what fails and where.
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
atomic-commit
TitusKirch
Commits the current session's working-tree changes as a series of atomic Conventional Commits in the repo's own detected conventions (scopes, types…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
merge-deps
TitusKirch
Triages and merges a repo's open dependency-bot pull requests — on GitLab, merge requests — selected strictly by author so no human's and no other bot's…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
prune-branches
TitusKirch
Reports a repo's stale branches grouped by why they are stale — merged into the integration branch (squash and rebase merges included), upstream gone, a…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
prune-comments
TitusKirch
Finds comments made redundant by the code beneath them — plain restatements, name echoes, banners, signature echoes — and reports them as removal candidates…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
pull-request
TitusKirch
Creates a pull request — on GitLab, a merge request — from the current branch in the repo's own conventions, with an umbrella Conventional-Commits title and a…
SkillAFreshness: A★ 2Claude Code +9
Signals
- Stars
- 2
- Forks
- 0
- Open issues
- 0
- Last commit (this folder)
- Oct 12, 2026 (16 days ago)
- Last release
- Oct 24, 2026 (5 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/TitusKirch/skills
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from TitusKirch
- 0.594score
write-contributing
TitusKirch
Writes and maintains a repo's `CONTRIBUTING.md` in the house style — scaffolds one where none exists, reconciles an existing guide against the repo it…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
decide
TitusKirch
Closes the open decisions a run has already named by putting each one in front of the human as a select dialog — concrete options with the recommendation…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
compact-readme
TitusKirch
Compacts an existing, overstuffed README so the landing view reaches the install/run command in ~30 seconds without losing any information — detail moves into…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
write-readme
TitusKirch
Generates project READMEs in the kirchDev house style — centered hero header with emoji + bold tagline, a one-liner code-snippet hook, feature bullets with…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
tituskirch-skills-config
TitusKirch
Creates, reconciles, and drift-checks `.tituskirch-skills.json` — the committed, repo-root config the other TitusKirch skills read to pick forges, trackers…
SkillAFreshness: A★ 2Claude Code +9 - 0.594score
vhs-demo
TitusKirch
Creates and maintains a scripted, reproducible terminal-demo GIF for a CLI repo from a Charm VHS tape rendered headless via Docker — the .tape is the…
SkillAFreshness: A★ 2Claude Code +9
Cite this page
write-docs skill. Agent Mart. https://agentmart.dev/skills/tituskirch-write-docs (last updated 2026-10-24)