#1196 Add the .kb/taxonomy.yaml format with drift reporting and back-fill - #1210
Merged
Conversation
A knowledge base can now declare its intended assertion structure in `.kb/taxonomy.yaml`: domain paths with one-line descriptions, split between a reviewed `domains` block and a `provisional` block for domains not yet reviewed. Keys are relative to the assertions root and nest to any depth. The new `@williamthorsen/kb/taxonomy` entry point exposes `loadTaxonomy` and `writeTaxonomy`. Declaring domains preserves the file's existing comments, key order, and formatting, and leaves a path either block already declares as it stands. A taxonomy that is absent or declares nothing loads as empty rather than failing. A malformed key fails the load and names the file: a restated `content/assertions/` prefix, a leading or trailing slash, an empty segment, or a `.` or `..` segment.
A `kb check` finding can now describe the store itself. Such a finding is reported under every run, including one narrowed to selected paths, one narrowed by `--vs`, and one that matched no notes at all, where it follows the line explaining why nothing was checked. Findings about a note keep being reported only when the run covers that note. The `--json` report carries a `scope` field on every finding, absent for a finding about a note.
`kb check` now reports where a store's assertion folders and its declared taxonomy disagree. `taxonomy.undeclared` names a folder that holds notes but that no domain declares, `taxonomy.unused` a declared domain with no note at or beneath it, and `taxonomy.orphan` a declared domain whose parent is undeclared. All three are warnings, so drift is reported without failing the run, and all three describe the store rather than any one note, so a run narrowed to selected paths or to `--vs` reports them too. A store whose taxonomy is absent or declares nothing reports none of them, so the rules apply only to a store that has adopted a taxonomy.
Store resolution and flag-value parsing each move out of the `check` command into a module of their own, so a second command consumes them rather than restating them. The mapping from a note's path to its domain moves beside the taxonomy loader. The drift rules ask which domains a note set observes and back-fill asks which domains it implies; deriving both from one mapping is what keeps a back-filled taxonomy from reporting drift against the notes it came from.
`kb taxonomy init` derives a starting taxonomy from the notes a knowledge base already holds, so a taxonomy can be introduced to a populated store without every folder reporting as undeclared. Every folder holding notes is declared, along with each of its ancestors, under `provisional:` with no description, and a store back-filled this way reports no taxonomy drift. The command leaves an existing taxonomy untouched and exits 2 unless `--merge` is given, which adds only the domains that taxonomy does not already declare. `--kb <name>` selects a registered store; without it the nearest ancestor `.kb/` directory is used.
Readers can now find `.kb/taxonomy.yaml` documented in the `@williamthorsen/kb` README: its two blocks, the key format and what fails to load, what provisional means, the three drift rules, and `kb taxonomy init`. The `kb-curate` skill names those rules in its rule-code table and points at `kb taxonomy init` as their follow-up. The README's export table also lists `./layout`, which it had omitted, and states the right number of entries.
A `.kb/taxonomy.yaml` whose `domains:` or `provisional:` header has nothing under it now loads as declaring nothing, matching an absent block. Promoting the last entry out of a block leaves exactly that shape, and it previously failed the load, so `kb check` exited 2 with every other check unrun and `kb-curate` reported `invalid-config`. `kb taxonomy init --merge` fills such a block in place, keeping it where it sits and preserving any comment attached to it. A load failure caused by a malformed block now names the key at fault.
`kb taxonomy init` now refuses a knowledge base the `kb.yaml` registry marks `readonly`, exiting 2 rather than writing `.kb/taxonomy.yaml` into it. A user who marks a vault they mirror or do not own now gets the same guard from it that `kb-curate --apply` already gives.
The helper prose now counts six detection categories and names `taxonomy.yaml` among the files whose defects surface as `invalid-config`, matching what the skill already documents.
Declaring a domain into a `.kb/taxonomy.yaml` whose `domains:` or `provisional:` block holds a scalar or a sequence now fails with an error naming the block, and leaves the file as it stands. Such a block previously had its contents replaced by the new declarations and reported as a clean write, so a domain list written as a YAML sequence was lost without a message. A comment written on a block header stays on that header line when the block is filled, rather than moving below the first declaration written into it.
`kb taxonomy init` now refuses a knowledge base marked `readonly` in `kb.yaml` when it is discovered from the working directory, not only when named with `--kb`. Running it from inside a vault marked readonly is the likelier invocation of the two, and it previously wrote. A `kb check --json` report of a discovered store now carries that store its registry name, where it previously reported `null` for every discovered store.
`kb check --json` reports a discovered knowledge base's registry name, and no name when the directory is unregistered. Neither case was asserted, so a change collapsing the reported name would have left the suite green.
Dependency auditProduction dependency audit passed. |
williamthorsen
marked this pull request as ready for review
August 5, 2026 17:36
williamthorsen
added a commit
that referenced
this pull request
Aug 7, 2026
…ssembly-mcp-v0.2.4 codeassembly-v0.6.0 codeassembly-v0.6.0 - #794 feat: Guide kb-add note placement with the store's declared taxonomy (#1223) - #1111 feat: Declare which harnesses sync targets (#1221) - #1214 feat: Allow an artifact to belong to more than one collection (#1219) - #1186 drop!: Dissolve `common-mistakes` into its consumers' guidance (#1217) - deps: Upgrade all deps to latest version - #1203 fix: Bar acceptance-criteria revision prompts to genuine conflicts (#1212) - #1196 feat: Add the .kb/taxonomy.yaml format with drift reporting and back-fill (#1210) - #1165 feat: Make a vetted subset of the library declarable (#1207) - #1197 feat: Report the retired `harnesses:` frontmatter key from `validate` (#1204) - #963 feat!: Rename the harness id to rovo and qualify the frontmatter key (#1199) - #1188 drop!: Retire the bundled Bitbucket inline-comment script (#1198) - #1187 feat: Gate the boolean prefix on a test and add the tail rule it rests on (#1195) factory-v0.2.4 - deps: Upgrade all deps to latest version - deps: Upgrade all deps to latest version - #1209 refactor: Clear factory's remaining lint violations and retire both deferral lists (#1216) - #1208 refactor: Clear the visualizations lint violations and retire six rule deferrals (#1213) kb-v0.4.0 - #794 feat: Guide kb-add note placement with the store's declared taxonomy (#1223) - #1196 feat: Add the .kb/taxonomy.yaml format with drift reporting and back-fill (#1210) codeassembly-lifecycle-v0.3.0 - #963 feat!: Rename the harness id to rovo and qualify the frontmatter key (#1199) codeassembly-mcp-v0.2.4 - #1206 refactor: Retire fleet's lint deferrals (#1211) - #1200 tooling: Retire mcp's lint deferrals and prune the dead root entries (#1205)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Introduces
.kb/taxonomy.yaml, in which a knowledge base declares the structure of its assertions.kb checknow reports three kinds of drift between that declaration and the folders on disk: a folder that holds notes nothing declares, a declared area that holds no notes, and a declared area whose parent is undeclared. A knowledge base that already holds notes can adopt a declaration in one pass with the newkb taxonomy init, and--mergeadds only what an existing declaration omits.Why
A knowledge base had no way to state where its notes belong, so nothing could say whether a folder was deliberate or accidental, and nothing reported when the tree had drifted from intent. The
codingvault shows the result at scale: 111 folders for 353 notes, with lifecycle markers interleaved among topics and no check able to distinguish the two.An earlier attempt at this,
.kb/schema.yaml, decayed because it described what the record parsers already enforced, so nothing broke when it drifted. This change makes the declaration load-bearing instead: it is read at runtime, and disagreements with the tree are reported.Details
🎉 Features
.kb/taxonomy.yamldeclares intended structure as two disjoint maps:domainsfor reviewed declarations andprovisionalfor those declared but not yet reviewed, keyed by paths relative to the assertions root at any depth. Parents are not implied, and a path declared in both maps fails the load.kb checkreports taxonomy drift as warnings. Its findings can now describe the knowledge base rather than a single note, so they survive a run narrowed to selected paths, a--vsrun, and a run that matches no notes at all.kb taxonomy initderives a starting declaration from the notes a store already holds, covering every folder that holds notes along with its ancestors. Without--merge, a store that already declares a taxonomy is left untouched. A store the registry marksreadonlyis refused, matchingkb-curate --apply.@williamthorsen/kb/taxonomyexposes the loader and a comment-preserving writer, so a declaration can be extended without losing hand-written comments, key order, or formatting.kb-curatesurfaces the same drift, with its rule-code table and follow-up list covering it.♻️ Refactoring
kbsubcommands rather than restated per command.🧪 Tests
📚 Documentation
provisionaltodomains, the drift rules, and the new command.Closes #1196