# Project Documentation

> Write project docs — README, contributing guides, API docs, changelogs, inline docs — and reconcile existing docs after a change made them wrong. Owns doc drift from the change in front of you; a repo-wide doc-rot audit belongs to technical-debt-review.

- Skill: `swestash/project-documentation` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add swestash/project-documentation`
- Raw SKILL.md: https://api.skillmd.com/api/skills/swestash/project-documentation/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: SWEStash (https://skillmd.com/u/swestash)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/swestash/project-documentation

---


# Project Documentation

Help create and maintain documentation that makes a project understandable, usable, and contributable. Good documentation answers three questions: What is this? How do I use it? How do I contribute?

## Document Types

Identify which documents the project needs based on context:

| Document | When Needed | Audience |
|----------|-------------|----------|
| README.md | Every project | Users, contributors, evaluators |
| CONTRIBUTING.md | Open source or team > 3 | New contributors |
| API Documentation | Any project with an API | API consumers |
| CHANGELOG.md | Any project with releases | Users upgrading between versions |
| Architecture docs | Complex systems | New team members, future maintainers |
| Inline docs (JSDoc/docstrings) | Public APIs, complex logic | Developers reading the code |

Ask the user which they need. If unsure, start with README — every project needs one.

Two modes use this skill. **Authoring** creates a document that doesn't exist yet
(the four workflows below). **Sync** reconciles documents that already exist
because a change made them wrong — that's the next section, and it's the mode you
want when someone says "I changed X" rather than "write me a Y".

## The Documentation Strategy — What Ships and What Doesn't

Establish once with the user: **which artifacts are git-versioned, and which stay
internal.** Most projects accumulate both, and only one of them is readable by
someone who has the repo and nothing else.

| Typically versioned | Typically internal |
|---|---|
| README, contributing guide, API docs, changelog | Execution plans and phase breakdowns |
| ADRs and architecture docs | Findings/bug logs kept during a work session |
| Roadmaps the project chooses to publish | Scratchpads, handoff prompts, session notes |
| Runbooks and operational docs | Anything under a gitignored directory |

This boundary is not bureaucracy — it decides what vocabulary the project's own
artifacts are allowed to use. **A term is usable in a versioned file only if a
versioned file defines it.** When a plan lives outside the repo, its phases,
checkpoints, and task codes name a conversation, and a reader hitting `Phase 2` or
`CP1.3` in a comment or commit has nothing to resolve it against. Write what the
term means instead.

The reverse also holds and matters just as much: when a project *does* ship its
plan or roadmap, referencing it is good practice, not a leak. Check which case
you're in rather than assuming either — `git ls-files` answers it.

**On a greenfield project** nothing is tracked yet, so this is a decision to make,
not a fact to look up.

**Exit condition** — one line, then write the document in the same response:
*"Nothing is tracked yet, so `<term>` resolves to nothing for a reader; I've
written the meaning instead. Worth deciding whether the plan itself ships."*

**This is not a gate on authoring.** Raise the boundary, apply the safe default —
meanings rather than labels, which is never wrong and costs nothing to change — and
deliver the document. Never answer a request for docs with the boundary question
alone: the user asked for a README, and a README that avoids unresolvable
vocabulary is strictly better than a question. Ask when the answer would change
what you write; otherwise state the assumption and write.

`verification-before-completion`'s publish gate reads this boundary as its baseline
when checking a staged diff.

## Workflow: Sync After a Change

Docs don't rot evenly. They rot where a change moved something a document names,
and nobody reread that document. Work from the diff, not from a general sense
that the docs feel old:

1. **Derive the identifiers.** From the diff, list what a reader could be relying
   on: flags, env vars, config keys, endpoints, commands, script names, package
   and directory names, install/setup steps, public exported symbols. Include the
   **old** names — those are what the docs still say.
2. **Grep the doc set** for each: README, `docs/`, and inline docs.
3. **Triage each hit** — wrong (contradicts the code now), incomplete (the code
   grew, the doc didn't), or fine. Only the first two are yours.
4. **Reconcile**, smallest edit that makes it true. Reconciliation is not a
   rewrite, and it's not an excuse to restructure a document you happened to open.
5. **Verify links resolve** if you moved or added any.

**Check inventories before prose.** Prose gets reread when someone edits the
feature it describes; tables, diagrams, ADR indexes, project-layout blocks, and
endpoint lists do not. Machine-like lists are where drift accumulates silently and
where it's least visible — a paragraph that's half-wrong reads oddly, while a
table missing two rows reads perfectly.

**A clean grep is not an all-clear.** Docs use shorthand, globs, and brace
expansion (`/api/{users,orders}`), so a literal grep can miss a line that
documents exactly what you changed. When a document plausibly covers the area,
open the section and read it.

## Accuracy: what you write is a claim

Both modes. A doc is a set of assertions about the code, and a sweep can introduce
errors as easily as it removes them — a confidently-worded wrong sentence outlives
the stale one it replaced, because it looks freshly maintained.

- **No claim from recall.** Every factual sentence comes from something you read
  this session. If you're describing what an endpoint does, open the handler.
- **Enumerate from the source of truth.** Endpoints from the router file, scripts
  from listing the directory, packages from the manifest, flags from the arg
  parser. Don't rebuild a list from memory and spot-check it — build it from the
  source and let it be complete by construction.
- **Re-read your own doc diff against the code** before committing, with the same
  scrutiny you'd give a code hunk. This is where a wrong claim gets caught.

## Workflow: README

### Step 1: Analyze the Project

Before writing, understand what exists:

- Read the codebase structure, package.json/pyproject.toml/go.mod, and existing docs
- Identify the project type (library, CLI, web app, API, monorepo)
- Identify the tech stack and key dependencies
- Look for existing setup scripts, Docker files, or CI config
- Check for a license file

### Step 2: Write the README

Use the template at [templates/readme.md](templates/readme.md). Adapt sections based on project type:

**For a library/package**: Emphasize installation, quick start, API reference, and examples.
**For a web app**: Emphasize prerequisites, setup, running locally, and environment config.
**For a CLI tool**: Emphasize installation, usage with command examples, and configuration options.
**For an API**: Emphasize endpoints overview, authentication, and link to full API docs.
**For a monorepo**: Emphasize structure overview, per-package docs, and how packages relate.

Key principles:
- **Lead with value**: The first thing someone reads should explain what the project does and why they should care. Not the tech stack, not the folder structure.
- **Working examples**: Every code snippet should be copy-pasteable and actually work.
- **Mark unverified values outside the command, never inside it.** When you have to write a
  command before you can confirm a value (a repo URL, a version, a port), the marker goes on
  its own comment line above the block, or in prose beneath it — never inline in a command
  token. `git clone <repo-url> ⚠️` is not a command: pasted, it clones into a directory
  literally named `⚠️`. Write `# ⚠️ replace <repo-url> with the real remote` on the line
  above, or use an obvious placeholder the shell cannot mistake for an argument. A snippet
  that has been annotated into breaking is worse than one that says "I need to read
  `package.json` first" — the reader trusts it and it fails on them.
- **Prerequisites explicitly stated**: Don't assume Node 20, Python 3.12, or Docker are installed. State versions.
- **From zero to running**: A new developer should go from `git clone` to a working local instance by following the README, without asking anyone.

### Step 3: Verify

- [ ] Can someone who has never seen this project understand what it does from the first paragraph?
- [ ] Are all setup steps complete and in order?
- [ ] Do code examples actually work?
- [ ] Are prerequisites and versions specified?
- [ ] Is there a way to verify the setup worked (e.g., "you should see X")?

## Workflow: CONTRIBUTING.md

See [references/contributing-guide.md](references/contributing-guide.md) for the full guide on writing contributing docs.

## Workflow: API Documentation

When documenting an API:

1. **Inventory endpoints**: List all routes from the codebase (read router files)
2. **For each endpoint**: Method, path, description, request params/body, response shape, error codes, auth requirements
3. **Group by resource**: `/users/*`, `/orders/*`, `/products/*`
4. **Include examples**: Real request/response pairs, including error responses
5. **Output format**: Markdown for simple APIs, OpenAPI/Swagger spec for complex ones

Suggest using the `api-design` skill if the API doesn't exist yet and needs designing.

## Workflow: CHANGELOG

Follow Keep a Changelog conventions:

- Group changes under: Added, Changed, Deprecated, Removed, Fixed, Security
- Newest version at the top
- Link version headers to git comparison URLs
- Write entries from the user's perspective, not the developer's

See [templates/changelog.md](templates/changelog.md) for the format.

**First check whether the project generates this file.** A `release-please-config.json`,
`.changeset/`, `.releaserc*`, or `cliff.toml` means the changelog is derived from commit
history, and hand-editing it — including keeping an `[Unreleased]` section alongside —
throws away the guarantee the tool exists to provide and reintroduces drift. There, the
entry is the **commit subject** (for squash-merges, the PR title) and the work is writing
that well; the reasoning goes in the commit body, not the changelog. Say so and stop.

When the changelog *is* hand-maintained, accumulate entries under `[Unreleased]` as
changes land. Writing them is this skill's work even when they must be reconstructed from
git history — read the log since the last tag, drop trivial commits (merges, typo fixes),
and translate the rest into user-perspective entries under the sections above. Hand off
only the release mechanics (version choice, tagging, publish automation) to
`release-management`.

## Workflow: Inline Documentation

For code-level documentation (JSDoc, Python docstrings, Go doc comments):

- **Document public APIs**: Every exported function, class, and type
- **Skip obvious code**: Don't document `getName()` returning a name
- **Document the why — at the altitude it belongs**: this is where inline docs go
  wrong most often. The why of a *line* belongs on the line: why this parameter
  exists, why this comparison is written the strange way it is, what the caller
  can't see. The why of a *system* — why the component exists, which alternatives
  were rejected, how it relates to other services — belongs in an ADR or
  architecture doc, and the code carries a pointer to it:
  `// Triage state lives in a separate writable DB; see ADR-018.`
  A design rationale pasted into a file header is unfindable (nobody greps source
  for "why two databases"), unreviewable (it never gets the scrutiny an ADR gets),
  and rots first — nobody re-reads a file header while editing line 300.
- **Include examples** for non-obvious usage
- **Document exceptions/errors**: What can go wrong and under what conditions
- **Use vocabulary the reader can resolve**: no phase names, checkpoint IDs, or
  task codes that no versioned document defines (see The Documentation Strategy)

## Principles Applied

- **KISS**: Write the minimum documentation that makes the project usable. Don't over-document internals.
- **DRY**: Don't duplicate information across docs. Link between documents instead.
- **YAGNI**: Don't write architecture docs for a 200-line script. Match documentation depth to project complexity. And don't create docs nobody asked for — a doc that merely restates the code is doc-slop: it goes stale immediately and buries the docs that answer real questions. Every document must answer a question someone actually has.

## Cross-Skill References

- `architecture-design` — the ADR a system-level rationale belongs in, rather than a source-file header
- `architecture-documentation` — C4 diagrams and docs-as-code for the architecture docs this skill points at
- `verification-before-completion` — the doc-drift and publish gates that read the versioned/internal boundary above
- `technical-debt-review` — a repo-wide doc-rot audit, as opposed to the drift from the change in front of you

