kb-authoring: sciagawka frontmattera OKF v0.1, taksonomia typow z rozstrzygnieciami decision/incident/runbook/audit wyciagnietymi z historii migracji (SPLIT commity), domyslne visibility: private, przypomnienie o check_okf.py po kazdej zmianie. Odrebne od kb-publish (to dotyczy pisania zrodel, nie wystawki public). new-doc.sh: scaffolduje kb/<type>s/<slug>.md z poprawnym frontmatterem, waliduje type, odmawia nadpisania, dokłada as_of dla type: audit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UXe8RXn1YDY2HAnX3RVwVS
7.9 KiB
| name | description |
|---|---|
| kb-authoring | Conventions for writing/editing source knowledge-base documents under kb/**/*.md (frontmatter schema, type taxonomy, visibility default, validation). Trigger whenever creating or editing a file under kb/ — this is about authoring the sources, not publishing kb-site (see kb-publish for that). |
Scope
This skill governs writing kb/**/*.md documents themselves — the OKF-format
knowledge base sources. It is not about publishing them: for "should I run the
publish script", see the kb-publish skill, referenced again at the bottom
here.
docs/sessions/*.md files use type: session-log frontmatter and are validated
by the same script, but they are not kb/ documents — they are a running
diary of work sessions. Never convert a session log into a kb/ doc and
never move/copy a kb/ doc's content into docs/sessions/. If material in a
session log deserves a permanent home (a decision, an incident writeup, a
runbook), write a new file under kb/ that captures it properly — don't
relocate the diary entry.
Frontmatter schema (OKF v0.1)
Every kb/ document opens with a YAML frontmatter block (--- ... ---) as
the first thing in the file. Validated by scripts/kb/check_okf.py — read
that file if you need the exact rules; summary:
| Field | Required | Values | Notes |
|---|---|---|---|
okf |
yes | "0.1" |
Pinned. Always this literal string, quoted. |
type |
yes | one of the taxonomy below | Determines which kb/<type>s/ directory the file lives in. |
visibility |
yes | private | public |
Default is private. See below — never default to public. |
status |
yes | active | deprecated | planned |
planned = decisions not yet made / work not yet started. deprecated requires superseded_by. |
updated |
yes | YYYY-MM-DD |
Bump every time you edit the file's content. |
links |
yes (may be []) |
list of paths | Relative to this file's own directory, e.g. ../phases/backlog.md or sibling-doc.md. Every entry must resolve to an existing file — check_okf verifies this. |
as_of |
only for type: audit |
YYYY-MM-DD |
Required exactly when type: audit, forbidden otherwise. See "audit" below for why this is a separate field from updated. |
superseded_by |
only when status: deprecated |
free text or path | Required exactly when status: deprecated, forbidden otherwise. Points to whatever replaced this doc (a doc path, or prose describing the replacement if there's no single successor file). |
contradicts |
optional | list | Free-text notes about known conflicts with other sources (e.g. "CLAUDE.md says X, but the directory doesn't exist"). Entries that look like a .md path (contain / and end in .md) are checked for existence like links; plain-text entries are not. |
stub |
optional | bool | Marks a doc as a placeholder/incomplete. Must be a real YAML bool (true/false), not a string. |
Type taxonomy — kb/s/
type |
Directory | What goes here |
|---|---|---|
node |
kb/nodes/ |
One doc per physical/virtual host — role, configured services, runtime data paths. Mirrors hosts/<node>/. |
service |
kb/services/ |
One doc per deployed service — what it is, how it's used/configured. Mirrors services/<svc>/. |
subsystem |
kb/subsystems/ |
Cross-cutting architecture/design docs describing how something works in general (access model, agent system, deployment conventions) — not tied to a single node or service. Kept in sync with current reality (unlike audit, see below). |
decision |
kb/decisions/ |
A choice that was made (or is still open, status: planned) plus its rationale — forward-looking, governs future behavior. Gets edited in place and re-dated as the decision evolves; it is not a historical log of what happened. |
incident |
kb/incidents/ |
A factual account of something that broke: symptom, root cause, fix/status, at a point in time. Slug conventionally date-prefixed (YYYY-MM-DD-short-description.md) since incidents are anchored to when they happened. Content generally stays close to the as-happened account rather than being rewritten into "current state" prose. |
runbook |
kb/runbooks/ |
Step-by-step operational procedure — deploy, install, recover, troubleshoot. Imperative, command-heavy, meant to be followed live. |
phase |
kb/phases/ |
A project/milestone plan broken into steps, tracking progress (including backlog/roll-up index docs). |
audit |
kb/audits/ |
A point-in-time snapshot of actual/verified state (ground truth recon), never an ongoing description. Requires as_of — the date the finding was true — kept distinct from updated (the date the doc text was last edited) precisely because an audit's findings can go stale even when nobody touches the file. Slug conventionally date-suffixed (topic-YYYY-MM-DD.md). |
session-log also exists as a type value (for docs/sessions/) but is out
of scope for kb/ — see Scope above.
Decision vs incident vs runbook vs audit — how ambiguous cases got resolved
This came up repeatedly during the kb/ migration (docs that mixed genres got split, not force-fit into one type):
- decision vs incident: a doc that both narrates "here's what broke" and
states "here's the guardrail we adopted because of it" is two documents.
Split the incident account into
kb/incidents/, keep (or extract) the resulting decision/guardrail intokb/decisions/. Example:home-assistant/DESIGN.md→kb/decisions/ha-configs-as-code.md+kb/incidents/2026-07-22-ha-dwie-instancje.md. - decision vs runbook: if a decision doc contains a reusable operational
recipe (install steps, recovery procedure), that section is a runbook, not
part of the decision's rationale. Split it out. Example:
deploy-runner→kb/services/job-deploy-runner.md(how it works) +kb/decisions/deploy-runner-uzasadnienie.md(why) +kb/runbooks/deploy-runner-install.md(how to install/operate it). - subsystem vs audit: a
subsystemdoc is the maintained description of how something is designed/intended to work — you keep it in sync. Anauditis a frozen investigation result ("I checked X on this date and found Y") — you don't rewrite it as things change, you write a new audit or a decision/incident instead. This is whyauditgot its ownas_offield distinct fromupdated. - When in doubt, prefer splitting a doc across two types over stretching one
type's frontmatter to cover mixed content — that's the pattern the
migration itself followed (see git log
feat(kb): SPLIT ...commits for worked examples).
Visibility default: private
visibility defaults to private. Every new document must be written
private unless the operator has explicitly and consciously decided it
should be public — never infer or default to public on your own, even if
the content looks harmless. visibility: public documents are the only ones
scripts/kb/gen_pages.py will ever emit to the public kb-site (fail-closed:
missing/unparseable/unrecognized visibility is treated as private).
After every change to kb/**/*.md
Run the validator and fix anything it flags before considering the edit done:
python3 scripts/kb/check_okf.py
It checks frontmatter parses, okf is pinned, type/visibility/status
are from their closed lists, dates are well-formed, as_of/superseded_by
are present exactly when required, and every links/path-like contradicts
entry resolves to a real file. A red run means something is broken — fix it,
don't skip it.
Creating a new document
Use scripts/kb/new-doc.sh <type> <slug> [--public] to scaffold a
correctly-placed file with valid frontmatter, then fill in the content.
If you just made a public change
If a file you created or edited carries visibility: public, don't forget
the KB site itself doesn't update on its own — see the kb-publish skill for
the one-line reminder to run scripts/kb/publish.sh.