251e597c63
Files changed: - CHANGES.md - VERSION - kb/CONTRACT.md - kb/entities/projects/kfchou/wiki-skills.md - kb/entities/projects/llm-wiki-skills.md - kb/entities/projects/vanillaflava/wiki-skills-vanillaflava.md - kb/entities/projects/wiki-skills-vanillaflava.md - kb/entities/projects/wiki-skills.md - kb/entities/projects/yugasun/llm-wiki-skills.md - kb/log.md - tools/CONTRACT.md - tools/chemenu/commands/index_build.py - tools/chemenu/commands/page_ops.py - tools/chemenu/kb_scan.py - tools/chemenu/lint_core.py - tools/chemenu/tests/test_index_build.py - tools/chemenu/tests/test_kb_scan.py - tools/chemenu/tests/test_lint.py - tools/chemenu/tests/test_page_ops.py - tools/chemenu/tests/test_type_resolver.py - tools/chemenu/type_resolver.py
278 lines
16 KiB
Markdown
278 lines
16 KiB
Markdown
# kb/ - Knowledge Layer Contract
|
|
|
|
The compiled knowledge layer, and the third stage of the pipeline
|
|
`raw/` -> `kb/` -> `reports/`. Everything here is written and maintained by the LLM from
|
|
material in `raw/`, and is expected to stay correct without being re-derived.
|
|
|
|
**Quality goal:** a page should answer a future question *without* re-reading the source it
|
|
came from. If answering still requires the raw file, the page is incomplete.
|
|
|
|
This file holds the rules that apply in **every** collection **and in every instance**. That
|
|
second half is the cut: what is written here is enforced by `tools/wikitool` or follows from
|
|
how it works, so it is identical everywhere and `dist export` ships it verbatim.
|
|
|
|
**What an instance decides for itself is next door, in
|
|
[kb/CONVENTIONS.md](CONVENTIONS.md)** - the language pages are written in, the headings its two
|
|
generated regions render under, the naming forms, the tone, the confidence rubric. That file binds exactly as this one does; it is simply owned by the instance
|
|
rather than by the stack, so the distribution ships only its `.template` and the instance writes
|
|
the real one. Read both, plus the target collection's `kb/<name>/COLLECTION.md` (also
|
|
instance-owned), before writing or editing a page.
|
|
|
|
The split is by **who may change the sentence**, not by what it is about. Language, tone and
|
|
naming used to sit here, which meant every instance that answered "not German" to
|
|
`setup-instance.md` was locally editing a file the stack also ships - and a merge from upstream
|
|
would quietly hand it back.
|
|
|
|
Structural facts (which frontmatter fields exist, which are required, what the body skeleton
|
|
looks like) are in neither - they belong to the type-specs and are printed by
|
|
`tools/wikitool types describe <type>`. Never hand-write frontmatter; scaffold with
|
|
`tools/wikitool new <type> --name "<Name>" --set field=value ...`.
|
|
|
|
## Collections
|
|
|
|
`kb/` is a **namespace, not a collection**. It carries no `COLLECTION.md` of its own.
|
|
|
|
A directory under `kb/` is a **collection** exactly when it contains a `COLLECTION.md`. That
|
|
file is the local authoring contract for every page in the subtree, and it belongs to the
|
|
instance: it declares in its frontmatter which profile from
|
|
[instructions/kb-profiles.md](../instructions/kb-profiles.md) it adopted, and whether the stack
|
|
resolves against it by name.
|
|
|
|
| Field | Means |
|
|
|---|---|
|
|
| `profile:` | Which catalogue entry this contract started from, or `none`. Free text - the catalogue is a palette, not an enum, and a collection an instance invented has no entry to name |
|
|
| `required_by_stack:` | Whether `wikitool` itself depends on this collection *by name*. Not the instance's to choose: `docs verify` checks it against the stack's own list. `kb/sources/` is `true` - `sources coverage`, `[^cite-id]` resolution and `kb/provenance.md` all resolve against that name - and everything else is `false` |
|
|
|
|
- A subdirectory *inside* a collection is an **area**. It inherits the enclosing contract and
|
|
must not carry a `COLLECTION.md` of its own - `kb/entities/systems/` is an area of
|
|
`kb/entities/`.
|
|
- **An area is as deep as a page goes.** `kb/<collection>/<page>.md` and
|
|
`kb/<collection>/<area>/<page>.md` are the two depths a page may sit at; nothing goes a level
|
|
deeper. A further subdirectory is not a second-level area - it is invisible to the generated
|
|
catalog, which reads exactly two path segments below `kb/` and folds anything past them into
|
|
the area's own table silently, with no location of its own (Gitea #57). That is why
|
|
`wikitool lint`'s `nested_pages` finding is a hard error rather than an advisory one like
|
|
`misplaced_pages`: a misplaced page still catalogs correctly from the wrong place, a nested
|
|
one makes the catalog itself wrong. A grouping axis that does not come from a type-spec's
|
|
`layout:` - project owner was the case that surfaced this - does not earn a second directory
|
|
level; it goes into frontmatter instead.
|
|
- A `COLLECTION.md` nested inside another collection is invalid.
|
|
- `COLLECTION.md` appears **nowhere outside `kb/`**. `raw/`, `types/`, `tools/`, `reports/`
|
|
and `instructions/` are not collections and carry a `CONTRACT.md` or a root type-spec
|
|
instead.
|
|
|
|
`tools/wikitool docs verify` enforces all three.
|
|
|
|
| Collection | Holds | Contract |
|
|
|------------|-------|----------|
|
|
| `kb/entities/` | Concrete things: projects, deployed systems, tools, technologies, people | [entities/COLLECTION.md](entities/COLLECTION.md) |
|
|
| `kb/concepts/` | Architectures, patterns, protocols, workflows, decisions, recurring problems | [concepts/COLLECTION.md](concepts/COLLECTION.md) |
|
|
| `kb/sources/` | One summary page per ingested source, carrying its `raw_files:` provenance | [sources/COLLECTION.md](sources/COLLECTION.md) |
|
|
| `kb/comparisons/` | Structured comparisons of two or more existing pages | [comparisons/COLLECTION.md](comparisons/COLLECTION.md) |
|
|
|
|
The four rows above are this instance's collections, not a fixed set. **Adding one:**
|
|
`mkdir kb/<name>` and write a `kb/<name>/COLLECTION.md` with the two fields above. Collections
|
|
are discovered by contract presence, so no code change is needed. A collection only becomes
|
|
*writable* once some type-spec declares a matching `base_dir:`. Renaming or dropping one is the
|
|
instance's call too - except where `required_by_stack: true` says otherwise.
|
|
|
|
**Where a page goes** is decided by its type-spec, never by hand - see
|
|
[types/type-spec.md](../types/type-spec.md).
|
|
|
|
## Generated files
|
|
|
|
Never hand-edit these; they are produced by `tools/wikitool`:
|
|
|
|
| File | Produced by |
|
|
|------|-------------|
|
|
| `kb/index.md` | `wikitool index rebuild` - the catalog **map**: statistics, counts, links |
|
|
| `kb/<collection>/INDEX.md` and `kb/<collection>/<area>/INDEX.md` | `wikitool index rebuild` - the page tables |
|
|
| `kb/log.md` | `wikitool log append` |
|
|
| `kb/provenance.md` | `wikitool sources rebuild-index` |
|
|
|
|
To *find* a page, search rather than read the catalog: `tools/wikitool search "<text>"`, or
|
|
`tools/wikitool search --field <predicate>` for a structured query over frontmatter.
|
|
|
|
## Titles are identifiers
|
|
|
|
**The filename stem *is* the page title, and `[[wikilinks]]` must match it exactly.** That is
|
|
not a naming preference; it is the wiki's only way to address a page. `wikitool lint` reports an
|
|
H1 that stops matching its title, `rename`/`rm` rewrite every reference to a stem, and a
|
|
`[^cite-id]` resolves through one.
|
|
|
|
Which *form* those titles take - spaces or kebab-case, singular or plural, what prefixes a
|
|
decision record - is the instance's, in
|
|
[kb/CONVENTIONS.md § Naming](CONVENTIONS.md#naming).
|
|
|
|
## Every page should
|
|
|
|
- [ ] Carry a clear, descriptive title and a summary near the top
|
|
- [ ] Use consistent terminology with the rest of the wiki
|
|
- [ ] Link to the entities and concepts it mentions, and declare an edge where the relationship
|
|
is worth naming - in the direction this page asserts it, not in both
|
|
- [ ] Cite its hard facts (see [Provenance and citation](#provenance-and-citation))
|
|
- [ ] Duplicate no existing page
|
|
- [ ] Appear in the catalog (guaranteed by `wikitool index rebuild`)
|
|
|
|
## Quotation cap
|
|
|
|
At most 2 blockquoted lines per page. `wikitool lint` reports overages as advisory, since
|
|
exceeding the cap can be a legitimate judgment call - but the page should carry the knowledge
|
|
itself, not delegate it to quotations. The cap is about how much of the page you let quotes
|
|
carry; it does not apply to text you are citing verbatim from a source.
|
|
|
|
The register those lines are written in - what counts as a buzzword, what filler is refused -
|
|
is the instance's, in [kb/CONVENTIONS.md § Tone](CONVENTIONS.md#tone).
|
|
|
|
## Language and identifiers
|
|
|
|
*Which* language pages are written in is [kb/CONVENTIONS.md](CONVENTIONS.md)'s to say. What
|
|
follows here is the part that is not a choice, because the tool resolves against it.
|
|
|
|
Every line of a page is either **prose** or an **identifier**. Only prose is translated.
|
|
|
|
**Prose:** descriptions and definitions, `## Key Information` values, `## Details` body text, a
|
|
source page's Summary / Key Takeaways / Action Items / Not Extracted, and `summary:`.
|
|
|
|
**Identifiers - never translated, in any language:**
|
|
|
|
| Identifier | Why |
|
|
|---|---|
|
|
| Page titles, and the H1 that repeats one | A title is the wiki's only identifier for a page and follows the subject's own established name - see [Titles are identifiers](#titles-are-identifiers). `wikitool lint` reports an H1 that stops matching its title |
|
|
| The subtype value on the generated `**Typ:**` line | It renders a schema enum value (`technology`, `workflow`), which `search --field` filters on. The label is prose; the value is not |
|
|
| `tags:` | Search keys, not prose |
|
|
| Commands, paths, config keys, hostnames, code | They are what they are |
|
|
| Quotations | Quoted verbatim in the source's own language |
|
|
|
|
Which foreign technical terms stay untranslated inside that prose is a judgment call the
|
|
instance records - see [kb/CONVENTIONS.md § Language](CONVENTIONS.md#language).
|
|
|
|
**A source in another language** is still summarized in the KB language: a source page is
|
|
evidence *about* a source, not a substitute for it. Quote verbatim in the original language and
|
|
record the raw file's language in `source_language:`.
|
|
|
|
### Generated regions
|
|
|
|
Two regions of a page body are **generated**, not authored: the links region `xref` owns and the
|
|
footnotes region `cite` owns. Each sits between a marker pair:
|
|
|
|
```markdown
|
|
<!-- wikitool:links -->
|
|
## Beziehungen
|
|
|
|
- **depends-on:** [[Hermes]]
|
|
<!-- /wikitool:links -->
|
|
```
|
|
|
|
The marker is what the tool locates the region by, and everything between the markers -
|
|
**heading included** - is replaced wholesale on the next write. An author never edits inside
|
|
them; anything left there is overwritten without warning, exactly as in `kb/index.md`. A region
|
|
with nothing to show is absent rather than empty.
|
|
|
|
The heading is therefore a *rendering* value, taken from `kb/CONVENTIONS.md`'s `sections:`. No
|
|
heading text exists in the compiler, and nothing matches on it: changing the declaration
|
|
re-renders the words on the next write and cannot split a page.
|
|
|
|
That is not how it used to work. The tool located these regions by matching their heading text,
|
|
which made a translated heading a structural fact - and made the region's *end* a guess. It ran
|
|
to the next heading, and before that to the end of the file, which silently deleted whatever sat
|
|
after it on eight pages. Any *other* heading a page carries is ordinary prose.
|
|
|
|
## Linking
|
|
|
|
**An edge is authored in one direction**, on the page that asserts it, and carries a label that
|
|
is a machine value rather than prose:
|
|
|
|
```yaml
|
|
related:
|
|
- depends-on: Hermes
|
|
```
|
|
|
|
Created with `tools/wikitool xref add --a "<A>" --b "<B>" --rel <label>`, never by hand-editing
|
|
`related:` or the rendered bullet. Say the sentence before choosing the label - `[A] <label>
|
|
[B]` - and if it only reads true backwards, the edge belongs on the other page.
|
|
|
|
**A reverse edge is a separate decision, not a mirror.** Write one when it independently helps a
|
|
reader at the other end; do not write one to make the graph symmetric. Navigation does not
|
|
depend on it either way: `index rebuild` renders the inbound view from the graph, completely and
|
|
without maintenance.
|
|
|
|
Which labels exist is [instructions/link-taxonomy.md](../instructions/link-taxonomy.md), a
|
|
palette that binds nothing. Which of them a page may *use* is its own collection's `outbound:`
|
|
block, per destination - the **source** collection decides, because the rules that govern an
|
|
edge are the rules of the collection asserting it. `xref add` refuses an unauthorised label and
|
|
`lint` reports one.
|
|
|
|
A page is expected to have at least one inbound edge; `wikitool lint` reports orphans.
|
|
Comparison pages are exempt - they are reached through the catalog. Directional edges mean more
|
|
pages qualify than under the old mirrored model, and that is the check measuring reachability
|
|
rather than measuring whether `xref` ran.
|
|
|
|
Renaming a page, deleting one, or dropping a single reference are tool operations with their
|
|
own procedure: see [instructions/page-lifecycle.md](../instructions/page-lifecycle.md).
|
|
|
|
## Provenance and citation
|
|
|
|
Every claim is either traceable to a raw file or explicitly marked as not.
|
|
|
|
- **`provenance:`** on every entity/concept page - `sourced` (every substantive claim traces
|
|
to a raw file), `general` (LLM general knowledge, no raw backing), or `mixed` (both; put the
|
|
unsourced part under a `## General Guidance (unsourced)` heading).
|
|
- **`raw_files:`** on every source page - concrete existing file paths under `raw/`, never a
|
|
directory and never a bare URL. For an external article also set `source_url:`, but
|
|
`raw_files:` must still point at the local copy under `raw/articles/`.
|
|
- **One source page may cover many raw files.** A folder of related documents becomes a single
|
|
page listing all of them, not one page per file.
|
|
- **A `[^cite-id]` footnote** appended to any *specific hard fact*: an IP, port, version, path,
|
|
command, or config value. `tools/wikitool cite add --page "<Title>" --source "Source - X"
|
|
[--file <qualifier>]` mints the id, upserts its `[[Source - X]]` (or
|
|
`[[Source - X|storage-model.md]]` for a multi-file source) definition in the page's trailing
|
|
Footnotes block (named per [Section headings](#section-headings)), and adds `Source - X` to
|
|
`sources:` - it prints the marker to paste at
|
|
the fact; placing it is still manual. Never hand-type a cite-id (AGENTS.md invariant 1). This
|
|
differs from a plain `[[Source - X]]` link, which only means "related to".
|
|
- **Notation inside code is notation, not a reference.** A `[^cite-id]` or a `[[wikilink]]`
|
|
written in backticks or a fenced block is read as an example: the citation does not count and
|
|
the link does not exist. That is what lets a page document this stack's own syntax. It also
|
|
means a marker appended to a line *inside* a fence cites nothing - put it on a source line
|
|
under the block (`<source-word>: [^cite-id]`, in the KB language), where it renders as a
|
|
footnote instead of travelling with the command when someone copies it.
|
|
- A source cited inline must also appear in the page's frontmatter `sources:` list;
|
|
`wikitool lint` checks this in both directions, and hard-errors on a leftover pre-migration
|
|
`^[[...]]` marker, an undefined `[^cite-id]` reference, or an orphaned Footnotes definition.
|
|
`tools/wikitool cite sync` reconciles a page's block after a prose edit changes which ids are
|
|
actually referenced.
|
|
- `tools/wikitool xref link-source --source "Source - X" --entities A,B,C` adds a new source
|
|
to every page it backs in one pass.
|
|
- Every raw file is expected to be claimed by some source page;
|
|
`tools/wikitool sources coverage` lists the ones that are not.
|
|
|
|
If no raw file or existing page backs an answer, say so explicitly rather than synthesizing
|
|
one - and never file the synthesized version back into the wiki.
|
|
|
|
## Confidence
|
|
|
|
`confidence_base` is the undecayed score set when a page's content is last confirmed;
|
|
`confidence` is *derived* from it by `tools/wikitool confidence decay` and must never be
|
|
edited directly.
|
|
|
|
Re-assess a page with `tools/wikitool touch --page "<Title>" --confidence-base <value>`.
|
|
|
|
What the number *means* - the base score, what raises it and by how much, and how to hedge in
|
|
prose below a threshold - is a rubric rather than a mechanism, so it is
|
|
[kb/CONVENTIONS.md § Confidence rubric](CONVENTIONS.md#confidence-rubric)'s.
|
|
|
|
## What does not belong here
|
|
|
|
- Raw source material - it stays immutable under `raw/`.
|
|
- Type definitions, frontmatter contracts, or templates - those live in `types/`.
|
|
- Procedures for operating the tooling - those live in `instructions/`.
|
|
- **Anything an instance would have to rewrite for itself** - language, naming forms, tone,
|
|
relationship labels, the confidence rubric. Those are `kb/CONVENTIONS.md`'s, and a sentence
|
|
of that kind here is a sentence the stack ships over the instance's own answer.
|
|
- Rules that apply to only one collection - those belong in that collection's
|
|
`COLLECTION.md`.
|
|
- Hand-edited generated files - see [Generated files](#generated-files).
|
|
- Generated lint reports - they are written to `reports/` and are not pages.
|
|
- Answers with no source behind them.
|