NAME
kb-index — generate a decisions/index.md from a directory of records
SYNOPSIS
kb index PATH [–stdout|–check]
kb index ROOT –all [–check]
DESCRIPTION
Regenerates PATH/index.md: one greppable line per record, newest first. The file is generated and never hand-edited.
Newest-first and one-line-per-record preserve the affordance a single top-inserted DECISIONS.md had — head, grep and awk reach the recent and the relevant without reading the whole corpus. The index is what stays loadable as the corpus grows; records are then read selectively.
Columns, in order: DR-
Every column always holds a value. An empty one renders as -, never as spaces: awk’s default separator is a run of whitespace, so a space-padded column is not a field at all and the next column silently takes its position. With the placeholder the title always starts at $7.
The supersession flag reads sup when superseded_by is non-empty, and - when it is not. It fires regardless of status, so it is redundant for a wholly superseded record whose status column already says so. Its real work is the partial case, where a record stays accepted because most of its episode still stands — without the flag such a record looks, in the index, exactly like one nothing has touched.
The index is built from the record files, so it works before any ingest. The attribution line names no tool: more than one generator has existed for this format, and a file naming one of them cannot be reproduced byte-for-byte by another without asserting something false about itself.
A record that cannot be parsed is an error, unlike in ingest. Dropping one silently would make the index lie about what the corpus contains.
This command writes index.md and nothing else. The format has no decisions/README.md, so one is never created.
–check compares PATH/index.md against a fresh render and reports drift as an error instead of writing: missing, or different from what the current records would produce. It exits 1 for either (a normal “no”: the index is out of date), so it fits a pre-commit hook or CI step; the remedy either way is running index without –check. A record that cannot be read or parsed is a failure, not drift, and exits with its own class instead: 65 for a malformed record, 66 for a PATH that is missing or not a directory. –check and –stdout cannot be combined.
–all walks ROOT and processes every directory that already has an index.md – the corpora that have opted into this convention – refreshing or, with –check, checking each one. A directory with record files but no index.md yet is silently left alone: –all never creates one, the same rule kb record set-status/supersede’s own automatic refresh follows. Nested corpora (each with their own index.md) are handled independently, never folded together. One bad corpus does not stop the rest: –all keeps going and reports every corpus, then exits non-zero if any needed attention, so a pre-commit hook can gate on the whole workspace in one call rather than naming each corpus by hand: 1 if the only trouble is stale indexes, and the class of the first failure (65 for a malformed record, 77 for a file it may not write) if any corpus could not be indexed at all, since a failure is more serious than drift. –all and –stdout cannot be combined. See TODO.md’s index-regeneration item (index –check and the auto-refresh on set-status/supersede) for the single-corpus half this completes.
Hidden directories are not descended into. A git worktree keeps a
whole second copy of the tree under .claude/worktrees/
OPTIONS
- –stdout
- write the index to standard output instead of index.md (PATH form only)
- –check
- verify index.md is current without writing it; exit 1 on drift
- –all
- process every already-indexed corpus under ROOT instead of one PATH
EXAMPLES
kb index clasm/decisions
kb index agents/decisions --stdout | head
kb index agents/decisions --check
kb index . --all
kb index . --all --check