Skip to content
Back to skills

Crit Doc Lint

ASecurity

Run the deterministic documentation-hygiene battery — twenty-one checks over links, orphan docs, the inbox, the roadmap, the memory logs, the pinned system tier and the agent definitions. The steward's cheap mechanical audit pass; use before a governance audit, at a session checkpoint, or after the doc tree was reorganised. The interpretive audits (redundancy, real drift, taxonomy, the cross-domain rollup) stay with the steward's own reasoning — this only runs the deterministic layer.

  • 3 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 5, 2026
developmentgobashgitdocumentation

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned October 5, 2026

npx -y skills add CritosAI/critos --skill crit-doc-lint --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Crit Doc Lint?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Crit Doc Lint
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/critosai-crit-doc-lint/badge)](https://www.skillsdirectory.com/skills/critosai-crit-doc-lint)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: crit-doc-lint
description: >-
  Run the deterministic documentation-hygiene battery — twenty-one checks over links, orphan docs,
  the inbox, the roadmap, the memory logs, the pinned system tier and the agent definitions.
  The steward's cheap mechanical audit pass; use before a governance audit, at a session
  checkpoint, or after the doc tree was reorganised. The interpretive audits (redundancy,
  real drift, taxonomy, the cross-domain rollup) stay with the steward's own reasoning — this
  only runs the deterministic layer.
---
<!-- SPDX-License-Identifier: Apache-2.0 · Copyright 2026 Criticaldrop Entertainment s.r.l. -->

# crit-doc-lint

Run the mechanical documentation-hygiene checks and interpret the output.

## How to run
```
bash ~/.claude/skills/crit-doc-lint/doc-lint.sh
```

Two rules hold for every check. A check that **could not run says `SKIPPED`**, never `(none)`: a
zero produced by a broken pipeline is not evidence. And every finding is a **flag for its owner,
never a gate**.

The output opens with the layout it found and a **provenance stamp** —
`### controls: CritOS@<tag-or-sha>[+dirty]`: which revision of the shared controls produced this
output. `+dirty` means the checkout the controls run from has uncommitted changes, so the output
may match no release.

## The twenty-one checks

1. **BROKEN** — a relative markdown link that does not resolve to an existing file. Code spans
   and fenced blocks are stripped first (a `](…)` fragment inside backticks is prose about
   links), and untracked `.md` files are scanned as sources too. Not detected, on purpose: a
   dead path written in backticks.
2. **PATH-IN-CODE** — a top-level `doc/….md` path hard-coded in code: it goes stale the moment
   the doc moves (reference by ID or concept, never by path). Exempt: `/archive/` paths, and a
   line annotated **`doc-lint:allow path-in-code`** — reserved for a path that is the program's
   I/O target; the annotation states its reason.
3. **ORPHAN** — a tracked `.md` that no other tracked `.md` links to: the other half of the
   *no floating doc* rule. Docs found by convention are exempt (README / CLAUDE / AGENTS /
   SKILL, the memory triad, the three registers, per-entity notes under
   `.critos/memory/a<N>/notes/`); a repo declares its own families in `.claude/doc-lint-exempt`
   (one regex per line). **An index entry must be a real markdown link** — an index written in
   backticks is reachable by eye and orphaned by graph.
4. **DANGLING-SKILL** — a `/skill-name` referenced in the skill layer (`SKILL.md` files and
   `CLAUDE.md`) that is not installed: a dead pointer inside the text the model reads to choose
   a skill.
5. **INBOX hygiene** — on the live inbox and its archives: **ping-pong** topics (≥3 hops with
   ≥2 reversals — another handoff will not settle them: name the owner or take a decision),
   `[OPEN]` entries with no **`Done when:`**, and **diffused ownership** (an entry addressed to
   several agents is held by nobody). A **⚰ RETIRED** inbox — first line carries `⚰` or
   `RETIRED` — is a signpost, not a channel, and is not audited.
6. **STALE-Rx** — an open `ROADMAP` row untouched for ≥10 days, measured by `git blame` on the
   row. The net under the lead's flip duty (`contract-shared § 2`). A flag means *re-verify with
   the lead*; re-verifying touches the row and resets its clock.
7. **BAD-TOKEN** — an inbox lifecycle token outside the closed vocabulary (live: `OPEN`,
   `PARKED-OWNED` · settled: `ABSORBED`, `CLOSED`, `ACK`, `FYI`, `SUPERSEDED`, `RETRACTED`). The
   owed-counter treats everything but the two live tokens as settled, so an ask under an
   invented token is owed by someone and counted by nobody. Also reports a valid but
   **unbolded** token as a format defect.
8. **STATUS-CHRONICLE (WARN)** — a `STATUS.md` over the line budget (200; per-repo override in
   `.claude/doc-lint-status-lines`) or stacking more than one dated *as-of* section. A STATUS is
   overwritten, not prepended; the fix is the owner's next checkpoint.
9. **STALE-STATUS** — a `STATUS.md` whose last commit is ≥14 days old. It means *re-verify with
   the owner*, never *this is wrong*: a snapshot legitimately rests while its domain is quiet.
10. **DANGLING-WIKI-LINK (WARN)** — a `[[slug]]` that resolves nowhere reachable. A slug
    resolves against a heading in a tracked `.md`, a tracked doc's basename, a table row id, a
    machine-local auto-memory note name, or `.claude/doc-lint-exempt`. WARN, because one of those
    namespaces lives outside the repo.
11. **TIER-3-LESSON** — an `accepted_rule` in a lessons log with no **`Enforcement: tier-N`**
    field. The field is read at its syntactic position — a line that starts with it, list marker
    and bold admitted. A rule about controls that is itself enforced by hope is the failure this
    check exists for.
12. **UNROTATED-LOG (WARN)** — a `DECISIONS.md` or `LESSONS-LEARNED.md` past the skimmable budget
    (1,200 lines; override in `.claude/doc-lint-log-lines`). The remedy is **rotation, never
    deletion**: move the oldest entries to `archive/<NAME>-archive-<period>.md` and leave a
    pointer. A log whose cited entries must stay may **declare** its overage in its own head —
    `DECLARED EXEMPTION — ACTIVE` plus why (the state word is the predicate, case-sensitive) —
    and is then reported as `DECLARED-OVER`, never silent. Also prints **`ARCHIVABLE`** info
    lines: entries marked fully superseded or completed still in a live log
    (`contract-memory § 2`).
13. **MEMORY-SHAPE** — a `.critos/memory/` child that is not `a<N>`, or an `a<N>` folder that no
    roster row maps (`contract-memory § 0`: one agent, one folder, one writer, one address).
14. **PIN-DRIFT** — a pinned `.critos/system/` file that differs from, or is missing against,
    what its **declared** release shipped, per `releases.manifest`. Never compared against HEAD:
    a project pinned at an older release verifies against its own release. The manifest is found
    from where the control itself lives — the project keeps no pointer to CritOS. Every
    can't-verify branch says `SKIPPED`. In the CritOS repository itself the check skips.
    Its second predicate, **VERSION-SPLIT**: a repo registered in `.claude/repos` whose pinned
    tier declares another release than this one — a migration covers the project as it is
    declared (`contract-system § 6`), and each repo's own pin check, verifying against the
    release it declares, cannot see the split. Read from the hub, one level.
15. **DEFINITION-PATH** — a `.md` path or an absolute path in an agent definition. A definition
    names its perimeter, never its interior (`contract-agent § 1`). Only these two classes are
    wrong without judgment; perimeter-versus-interior depth is the steward's review.
16. **RETIRED-REF** — a live doc whose link resolves to a file whose first line carries the
    ⚰/`RETIRED` marker: the link resolves, so [1] is green by design. Sources under `archive/`
    or `release/`, and the signposts themselves, are exempt. Most hits are legitimate history —
    triage, never a gate.
17. **COLD-LIVE-TOKEN** — an `[OPEN]` or `[PARKED-OWNED]` token in the token position of an
    ENTRY inside a `HANDOFFS` archive: owed by someone, counted by nobody, because the
    owed-counter reads the live inbox only. Restore a truly live entry, or close it where it
    lies. A line that only QUOTES the token — prose, or a settled entry retelling its past — is
    not a finding: those are counted on one line, never listed.
18. **DEFINITION-SHAPE** — an agent definition whose `##` sections differ from the template's:
    four mandatory (`1 · Purpose`, `2 · Domain`, `3 · What I do NOT do`,
    `4 · Write surfaces I touch`) plus the optional `5 · Standing directives`.
19. **DEFINITION-ACTOR** — a definition naming an actor other than itself. A definition names
    **domains, never actors** (`contract-agent § 1`); the roster resolves domain → agent.
20. **SHELF-INDEX** — a rostered **Shelf** address that does not resolve, or a README-indexed
    shelf folder holding tracked `.md` not reachable from the **index chain** (the index plus
    the READMEs it links, transitively; a link from a non-index sibling does not count). The
    list leg runs on `README.md` indexes only — any other entry point is legal and its
    completeness is the owner's. A shelf declared in prose with no link is itself a finding,
    unless the cell names another repo.
21. **CITED-ID** — a decision or lesson id (`ADR-…-NNN`, `L-…-NNN`) cited in a doc, a register
    or code that no `DECISIONS` / `LESSONS-LEARNED` log declares. Declared = a log's entry
    headings, archives included, plus the ids in a log's head (the alias table of a retired
    sequence; a whole sequence retired as `ADR-OLD-NNN -> ADR-A2-NNN` resolves every id of the
    prefix on the LEFT of the arrow, and only that one — the right side is the live sequence,
    where a typo must still fire), across every registered repo. Not read as citations: the pinned tier, the skills,
    templates, archives and the generated atlas. A rotation, a restructure and a split
    (`contract-memory § 7`) are the moments an id gets lost. An id of an unregistered repo is
    flagged: exempt it in `.claude/doc-lint-exempt`, or register the repo.

**Several repos.** If the repo registers others in **`.claude/repos`** (one path per line,
relative to the repo root; `#` comments), the whole battery is repeated in each — read-only, one
level: a registered repo's own registry is not followed.

## How to act on the output (the steward)

- **A finding on a surface you own** (doc organisation, registration, a moved path to re-point)
  → fix it and commit locally.
- **A finding on a domain's doc or code** → it is the owning agent's: write one line in the
  inbox (`.critos/shared/HANDOFFS.md`) and report it. Do not edit domain content.
- **A finding is a symptom** (`contract-session § 6`, ACTION): read its shape before choosing
  the action — the same broken link is repointed when its target moved and de-linked when its
  target died; a red on a pinned file asks for a migration, never an edit.
- Then apply the interpretive audits the script does not cover — redundancy, real drift, which
  doc is authoritative — with your own judgment.

Files in this skill

  • SKILL.md10.2 KB
  • doc-lint.sh43 KB
  • inbox-audit.mjs4.4 KB
  • token-audit.mjs3.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.