The day had three `## 2026-10-21` headings — three logs wearing one date, which is the sprawl the spec's one-dated-section rule exists to prevent. One date now, one `###` per campaign. `okf-maintenance.md` states the multi-campaign shape explicitly so nobody has to infer it, and names `AGENTS.md` as the co-owner of the entry law so an editor changes both. The new entry records what the dedupe sweep actually taught: an index that restates its own reference pages becomes the stale authority, and a subagent ledger is a claim until it is re-read against the file it accuses — most rows returned by the audit fan-out were checkably false, and half the ledgers never arrived at all. `skills/ecosystem.md` gains the `resource:` frontmatter the bundle's other externally-sourced pages carry. Refs #64
7.6 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | |||||
|---|---|---|---|---|---|---|---|---|---|
| guide | OKF Bundle Maintenance | Keep your OKF knowledge bundle from rotting — change tracking, frontmatter discipline, staleness detection, and automation. |
|
2026-10-19 |
OKF Bundle Maintenance
Knowledge bundles rot. It is the nature of knowledge to attract cobwebs, much like an unvisited pantry attracts spiders that are frankly doing you a favor by reminding you it has been a while. An OKF bundle maintained by agents is no exception — files drift out of sync, frontmatter becomes decorative, and index.md turns into a ghost town where links go to die.
The core principle: if you do not track changes, you do not know when they happened. If you do not have a changelog, you are the person who finds the broken thermostat and wonders why it is set to "volcano."
Change Tracking with log.md
Exactly one log.md per bundle, at the bundle root — okf-spec.md owns that rule
and scripts/kb-lint.sh enforces it, reporting any log.md that is not the root's. The
maintenance action is collapse, never coexistence: when a second log turns up (core/log.md,
notes.md, a per-run diary), move its entries into the root log under their own dates, delete
the file, and re-run the linter.
Format: one dated section per day, newest first; a few lines per change — what happened, and the durable lesson. It is not a file manifest.
# Bundle Change Log
## 2026-01-15 — the gate was reading the wrong files
A gate that gets an empty file list reports success. Law: a check MUST fail closed;
a silently-passing gate is worse than none, because it buys the belief of safety.
Details: [secret gate](/tools/index.md).
Rules:
- Newest entries first. Old entries at the top invert the timeline.
- What changed + the durable lesson, a few lines. Full narratives are recoverable
from git (
git log --follow log.md); never re-expand one in place. - Laws and incidents, never bookkeeping. No per-file inventories, no run-by-run numbers, no transcripts. Measured numbers still have to pass the purpose test.
- Link, do not duplicate. Knowledge that outlives the entry belongs on its concept page; the entry points there.
- One dated section per day (
## YYYY-MM-DD), and mentionindex.mdwhenever a file is added or removed. Several campaigns on one day share the section: a single##date, one###per campaign — three## 2026-10-21headings is three logs wearing one date. The entry law is also restated in the repo'sAGENTS.md(the always-loaded tier); change one, change the other.
Common Mistakes
- ❌
Updated ghostty.md— updated it with what, and what did it teach? - ❌ Forgetting the entry — the change lands undocumented and the next agent rediscovers the failure the hard way.
- ❌ Starting a second log in a subdirectory — the sprawl that makes logging useless.
- ❌ Invented paths in links — the RECOMMENDED form is an absolute bundle path
(
/tools/index.md), resolved against the bundle root; the mistake is a path that names no file there, and that is what the linter reports. - ❌ Re-expanding an old entry in place — the entry is a pointer; git is the transcript.
Frontmatter Discipline
Frontmatter is the metadata layer. It is not decoration.
Required field:
type— The concept type. The only strictly required frontmatter field.
Strongly recommended:
description— The preview text. Without it, the file is invisible and confusing.tags— Use for cross-cutting concerns. Tags hold things together across categories.timestamp— Include for staleness detection. A file with a timestamp from 2023 is more likely stale than one from 2026.title— Optional but helpful.
Rules:
- ✅ Every concept file must have a
description. - ✅ Use
tagsliberally but consistently. - ✅ Include
timestampon every file. - ✅ Pick descriptive
typevalues:reference,guide,configuration,tutorial. - ❌ Don't use
type: fileortype: document— be specific. - ❌ Never leave
descriptionblank or copy the title.
One Thing Per File
OKF is built on the principle that a file is one concept.
Splitting criteria:
- ✅ One topic, one file. If the content can be summarized in one sentence without using "and," it belongs in one file.
- ✅ Give each file its own
type. - ✅ Keep each file between 1 and 500 lines. Under 1 = over-split. Over 500 = under-split.
- ❌ Don't create a file called
misc.md—miscis a graveyard, not a category. - ❌ Don't use
# Otheror# Additional Notessections — these are taping things to the wall.
Quarantine, Not Deletion
A page is never deleted outright: it moves to .AGENTTRASH/ beside where it lived and
waits for a pruning session with Frank present. The quarantine is not part of the
bundle — scripts/kb-lint.sh and scripts/kb-coverage.py skip any path containing
.AGENTTRASH. That exemption is deliberate: a gate that goes green only once the
quarantined copy is gone is a gate that deletes history.
Auto-Generation Strategies
Index files as living documents:
find docs/bundle-name/ -name '*.md' ! -name 'log.md' -type f | \
sort | \
awk '{print "- " $0}' > docs/bundle-name/index.md
Staleness detection:
# Find files older than 90 days
find docs/ -name '*.md' ! -name 'index.md' ! -name 'log.md' \
-mtime +90 -type f -print
# Find files missing timestamp
find docs/ -name '*.md' ! -name 'index.md' ! -name 'log.md' \
-type f -exec grep -L '^timestamp:' {} \;
# Find files missing description
find docs/ -name '*.md' ! -name 'index.md' ! -name 'log.md' \
-type f -exec grep -L '^description:' {} \;
Version Control Best Practices
- ✅ One logical change per commit
- ✅ Write meaningful commit messages ("Updated file" is not a commit message. It is a shrug in text form.)
- ❌ Don't commit entire bundle dumps — a commit touching 50 files is a data dump, not a change
Useful git commands:
git blame -L 1,30 docs/ghostty.md # Who changed what and when
git log --oneline -n 10 -- docs/pi-permission-system/ # Last commits in a directory
git status --short # What is uncommitted
Knowing When Something Is Stale
| Signal | Threshold | Action |
|---|---|---|
timestamp field older than 6 months |
Auto-flag | Review and update or archive |
| File not modified in 12 months | Auto-flag | Assess whether still relevant |
index.md count differs from file count |
Always | Fix immediately |
log.md has no entries for 30+ days |
Context-dependent | Normal if no changes made |
Automated Gates (this bundle)
Two mechanical checkers live in scripts/; both exit non-zero on violations.
Run both before committing any omp-docs/ change; tests/kb-lint.bats pins
their behavior.
bash scripts/kb-lint.sh omp-docs # OKF conformance
python3 scripts/kb-coverage.py omp-docs # index coverage doctrine
- kb-lint — OKF v0.1 rules: non-empty
typefrontmatter on every non-index file, no frontmatter onindex.md, resolvable wikilinks and relative links, reserved names (index.md/log.md),YYYY-MM-DDlog headings. - kb-coverage — the AGENTS.md anti-rot mechanism: every directory has an
index.md, and that index links every sibling file and subdirectory.
See Also
- OKF v0.1 Specification — The complete format specification.
- Root Index — This bundle's structure and navigation.