Skip to content
Guide contents

Adopting in an Existing Project

← Guide index

How to retrofit docs-kit onto a repository that already has (some) design docs. For a fresh repository, Project setup is faster.

The principle — do not promote everything to current

The biggest failure mode when adopting existing docs is flipping them all to current at once.

current is a claim: “reconciled with the implementation.” Marking un-reconciled documents current means docs-kit is only guaranteeing the shape, while the AI keeps trusting stale content as spec. That is worse than before you installed it.

This is why docs-kit adopt always brings documents in as status: draft. Draft means “reference material; trust the code,” so the state right after adoption honestly says: nothing is guaranteed yet.

Leaving things at draft does no harm. Promoting one valuable document at a time settles faster than rushing everything.

The path

Step 0 — take inventory

Start by listing what exists.

find . -name '*.md' -not -path './node_modules/*' -not -path './.git/*'

Sort the results into three piles.

PileCriterionDestination
AdoptDescribes implementation specs, structure, or past decisionsOne of the four layers under docs/
Leave aloneREADME, contribution guide, release notes, end-user documentationStays put. Outside docs-kit’s remit
DeleteEntirely outdated, describes a feature that no longer exists, abandoned draftDelete now. Easier than moving it and deleting later

Make the “delete” calls at this stage. Trying to tidy up after adoption means they get buried in a pile of drafts and never touched.

For which layer, follow the decision flow in Workflow. Roughly:

ContentLayer
”Why we chose this approach,” “what we considered and rejected”adr/
”How it is supposed to behave now”spec/
”Overall structure and dependency direction”arch/
A work plan for what comes nextplan/ (or move it to an issue)

Step 1 — build the scaffolding with docs-kit init

docs-kit init

Existing files are never overwritten, so it is safe even with a docs/ already present.

created: docs.config.yaml
skipped: docs/adr/
created: docs/spec/
created: docs/arch/
created: docs/plan/
created: docs/INDEX.md
updated: CLAUDE.md
created: .github/workflows/docs-kit.yml
created: .claude/commands/docs-verify.md
created: .claude/commands/docs-catchup.md

If CLAUDE.md already exists, the <!-- docs-kit:begin v1 --> block is simply appended. Nothing else in the file is touched.

Then align docs.config.yaml with reality.

schemaVersion: 1
root: docs                 # document root. change it if docs live elsewhere
codeRoots: [src, app]      # top-level code directories
ignore:                    # files whose changes should not stale a doc
  - "**/*.test.ts"
  - "**/__snapshots__/**"
  - "**/fixtures/**"

Do not forget tests in ignore. Existing projects have a lot of them, and an empty ignore means everything is stale from day one.

If your docs are not in docs/

Change rootdocumentation/, design/, whatever.

root: documentation

What does not change is that the four layers adr/ spec/ arch/ plan/ must exist beneath it. Layer names are not configurable.

Step 2 — sort documents into the four layers

docs-kit adopt only looks at *.md directly inside <root>/<layer>/. Subdirectories are not scanned, so files have to be moved first.

Match the filename rules

LayerFilenameid
adr/NNNN-<slug>.mdADR-NNNN
spec/<slug>.mdSPEC-<slug>
arch/<slug>.mdARCH-<slug>
plan/<slug>.mdPLAN-<slug>

Slugs match [a-z0-9]+(-[a-z0-9]+)*lowercase alphanumerics and hyphens only. Spaces, uppercase, underscores, and non-ASCII filenames are all out.

git mv docs/design/EditingModel.md docs/spec/editing-model.md
git mv docs/decisions/adr-3-undo.md docs/adr/0003-undo-stack.md

Zero-pad ADR numbers to four digits (0003-undo.md, not 3-undo.md). Gaps in existing numbering are fine; only duplicates need resolving.

Rename with git mv. Keeping the history connected leaves room for later freshness checks to treat it as a pure rename.

Put assets in a subdirectory

Keep images and the like out of the layer directories. Subdirectories are not scanned, so they can sit there untouched.

docs/
├── spec/
│   └── editing-model.md
└── assets/                ← not scanned
    └── editing-model.png

Step 3 — add front matter with docs-kit adopt

docs-kit adopt
adopted: docs/adr/0003-undo-stack.md (id: ADR-0003, status: draft)
adopted: docs/spec/editing-model.md (id: SPEC-editing-model, status: draft)
adopted: docs/arch/overview.md (id: ARCH-overview, status: draft)
skipped: docs/spec/Editing Model.md (the filename does not match the naming rules; rename it or recreate it with docs-kit new)
adopt: 3 adopted, 1 skipped

(The skipped line means “filename does not match the naming rules — rename it or recreate it with docs-kit new.” The last line reads “3 stubs added, 1 skipped.”)

A stub is inserted at the top of each file.

---
id: SPEC-editing-model
title: Editing model
status: draft
---
  • id is derived from the filename
  • title comes from the first # heading in the body, or the filename if there is none
  • status is always draft

What adopt does not touch

TargetBehaviour
Files that already have front matterSkipped (if malformed, that is lint’s job)
Files whose name breaks the rulesReported, not touched. It never renames on its own
Files whose id is already takenReported, not touched
Subdirectories of layer directoriesNot scanned
The bodyNever modified. Only a stub is prepended

It is idempotent, so rename-and-rerun is a fine loop. Fix a skipped file, run adopt, repeat.

Step 4 — get lint green

docs-kit lint
docs/adr/0007-caching.md:E004 id "ADR-0007" and filename "0007-caching.md" do not correspond (expected ADR-0007)
docs/spec/api.md:E011 referenced id "ADR-0099" does not exist
docs/spec/legacy.md:W003 scope "vendor/**" points outside codeRoots [src] (warning)

Errors (E) must be cleared. Warnings (W) exit 0, so they can wait.

W002 (a scope that matches nothing) does not show up here: adopt leaves every document draft, and drafts are exempt. It starts applying as documents are promoted with verify.

Common right after adoption:

CodeCauseFix
E001Broken front matter (hand-written front matter predating adopt, etc.)Make it valid YAML
E004id and filename do not correspondAlign one to the other
E005Duplicate idChange the slug and rename
E007Unknown top-level fieldPrefix it with x- to keep it (owner:x-owner:)
E011depends_on references a nonexistent idFix the typo or drop the reference

E007 is the common one for existing docs. If you were writing author: or updated:, renaming them to x-author: / x-updated: preserves them verbatim (the tool holds them without interpreting).

docs-kit index && git add -A && git commit -m "docs: bring existing design docs under docs-kit (draft)"

Commit here. At this point every document is draft, so stale reports all skipped and CI passes.

Step 5 — promote to current, one at a time

This is the real work. Do not try to do all of it — go highest-value first, one document at a time.

Priority

  1. Specs for modules the AI touches often — the largest payoff
  2. arch/overview.md — you want the big picture trustworthy early
  3. ADRs that are still in force — no scope, so it is just a manual flip to current (cheap)
  4. Everything else

Per document

Concretely, add a scope to the front matter:

---
id: SPEC-editing-model
title: Editing model
status: draft
scope:
  - src/core/editing/**
---

Then, once the body has been read against the code and corrected:

docs-kit verify SPEC-editing-model
SPEC-editing-model: verified_at → 8f3a1c2 (promoted to current)

Choosing not to promote

Not every document needs to become current.

  • Too outdated to be worth fixing → delete it. git history keeps it
  • A successor exists → set status: superseded and superseded_by: SPEC-xxx
  • Still useful as background → leave it draft. The AI will treat it as reference

Leaving it at draft is a legitimate choice. “Nothing is guaranteed here” is stated accurately, which beats a fabricated current by a wide margin.

Delegating to the AI

With Claude Code connected, /docs-catchup can grind through much of this: per document, reconcile against the implementation, verify if it matches, fix then verify if it drifted. That said, writing the scope and making the final call are better left to a human.

Step 6 — tighten CI in stages

Making all three commands mandatory on day one turns CI red with stale and everyone stops looking. Go in stages.

Stage 1 — lint only

- run: docs-kit lint
- run: docs-kit index --check

Stops structural breakage. Everything is draft, so stale always passes anyway.

Stage 2 — run stale as a warning

- run: docs-kit stale || true

Look at the result without failing on it. As the number of current documents grows, the verdict starts carrying meaning.

Stage 3 — make stale mandatory

- run: docs-kit lint
- run: docs-kit stale
- run: docs-kit index --check

Move here once the current documents are broadly in place. From then on, “change the implementation, verify the doc” is enforced.

At every stage, fetch-depth: 0 is required.

- uses: actions/checkout@v4
  with:
    fetch-depth: 0

Step 7 — connect Claude Code

claude mcp add docs-kit -- docs-kit mcp

In an existing project the effect is immediately visible.

docs-kit which src/core/editing/model.ts
primary:
  SPEC-editing-model  current  8f3a1c2  docs/spec/editing-model.md
related:
  ADR-0003            current  -        docs/adr/0003-undo-stack.md

Even with 50 documents in docs/, the AI reads only the handful that came back.

Case by case

Monorepos

One config, at the repository root. Per-subdirectory docs.config.yaml files are not supported.

root: docs                          # one docs/ for the whole repository
codeRoots: [packages, apps]

Namespace per-package documents through the slug.

docs/spec/
├── web-editing-model.md      → SPEC-web-editing-model
├── api-auth.md               → SPEC-api-auth
└── worker-queue.md           → SPEC-worker-queue

scope then points at the package path.

scope:
  - packages/web/src/editing/**

Too many documents to handle

Adopting everything as draft and stopping there is fine. Even in that state:

  • Reverse lookup with which works (drafts are returned too)
  • The AI correctly treats drafts as reference material
  • CI runs on lint and index --check alone

Nothing gets worse than your current situation. Promote modules to current as you come to need them.

Documents that carry progress state

If checklists like “Phase 1: done ✅” are mixed in, move them out to the issue tracker. Progress state mixed into a design doc means every read requires distinguishing spec from status, and both humans and AI get it wrong.

Work plans themselves can live in plan/, but plan is disposable and expected to be deleted at merge. It is not for durable task tracking.

Existing front matter with a different schema

If static-site front matter (layout:, date:, tags:, …) is already present, adopt skips the file — it counts as already having front matter.

Add the required fields by hand and prefix anything docs-kit does not know with x-.

---
id: SPEC-editing-model     # added
title: Editing model       # existing title can be reused
status: draft              # added
x-layout: doc              # layout: → x-layout:
x-date: 2025-04-01         # date: → x-date:
x-tags: [editor]           # tags: → x-tags:
---

x- fields are preserved verbatim and never interpreted. verify rewrites line by line, so they survive intact.

Docs in a GitHub Wiki or a documentation site

docs-kit can only handle Markdown inside the same repository. The freshness check depends on git history, so documents in another repository or an external service cannot be covered.

To adopt them, move the design-doc content into the repository. End-user documentation is out of scope anyway and can stay where it is.

Confirming adoption

docs-kit lint && docs-kit stale && docs-kit index --check

All three green, and at least one current document. With zero current documents you have only fixed the shape; no freshness guarantee is doing any work yet.

docs-kit stale
ADR-0003            skipped  (no scope)
ARCH-overview       ok       (verified at 8f3a1c2)
SPEC-editing-model  ok       (verified at 8f3a1c2)
SPEC-legacy-api     skipped  (draft)

ok 2 / stale 0 / broken 0 / skipped 2

That shape means adoption is done. From here, run the loop in Workflow and whittle down the skipped count over time.

Next