Files changed: - .gitea/workflows/ci.yml - .wikitool-kb.json - AGENTS.md - CHANGES.md - INSTALL.md - README.md - VERSION - instructions/CONTRACT.md - instructions/dev/testing-conventions.md - instructions/german-terminology.md - instructions/kb-profiles.md - instructions/migrations/3.0.0-authoring-conventions.md - instructions/private-instance.md - instructions/setup-instance.md - instructions/wiki-ingest/SKILL.md - instructions/wiki-manage/SKILL.md - kb/CONTRACT.md - kb/CONVENTIONS.md - kb/CONVENTIONS.md.template - kb/comparisons/COLLECTION.md - kb/concepts/COLLECTION.md - kb/entities/COLLECTION.md - kb/sources/COLLECTION.md - tools/CONTRACT.md - tools/README.md - tools/chemenu/commands/dist_cmd.py - tools/chemenu/commands/docs_verify.py - tools/chemenu/commands/doctor.py - tools/chemenu/commands/new_page.py - tools/chemenu/conventions.py - tools/chemenu/kb_collections.py - tools/chemenu/kb_scan.py - tools/chemenu/provenance.py - tools/chemenu/sections.py - tools/chemenu/tests/conftest.py - tools/chemenu/tests/test_conventions.py - tools/chemenu/tests/test_dist_cmd.py - tools/chemenu/tests/test_doctor.py - tools/chemenu/tests/test_new_page.py - tools/chemenu/tests/test_types_cmd.py - types/comparison.md - types/concept.md - types/entity.md - types/source.md - types/type-spec.md
14 KiB
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 - the language pages are written in and its three
tool-owned section headings, the naming forms, the tone, the relationship-label vocabulary, 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 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.mdof its own -kb/entities/systems/is an area ofkb/entities/. - A
COLLECTION.mdnested inside another collection is invalid. COLLECTION.mdappears nowhere outsidekb/.raw/,types/,tools/,reports/andinstructions/are not collections and carry aCONTRACT.mdor 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 |
kb/concepts/ |
Architectures, patterns, protocols, workflows, decisions, recurring problems | concepts/COLLECTION.md |
kb/sources/ |
One summary page per ingested source, carrying its raw_files: provenance |
sources/COLLECTION.md |
kb/comparisons/ |
Structured comparisons of two or more existing pages | 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.
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.
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 every entity and concept it mentions, and be linked to in return
- Cite its hard facts (see 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.
Language and identifiers
Which language pages are written in is kb/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. 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.
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:.
Section headings
Three headings are a vocabulary the tool owns rather than prose an author picks: xref add
writes into Relationships and See Also, and cite add owns the trailing Footnotes block. They
follow the KB language like everything else, so the instance names them, in
kb/CONVENTIONS.md's sections: frontmatter. tools/chemenu/conventions.py reads that
declaration and tools/chemenu/sections.py is what the rest of the compiler asks - there is no
heading text in the compiler itself.
Each has aliases the tool still recognizes but no longer writes, which is what lets the corpus
be translated page by page: a page still carrying ## Relationships is found and appended to
correctly, and cite sync leaves an untranslated ## Footnotes heading alone rather than
retitling it. The recognized set is the canonical name, any section_aliases: the instance
declared, and the names this stack wrote before the declaration existed. Renaming a heading is
the translation pass's job, never a side effect of another command. Any other heading an
author adds is ordinary prose and is translated with the rest.
Linking
Every page links to what it mentions, in both directions. Cross-references are created with
tools/wikitool xref add --a "<A>" --b "<B>" --rel-a "<label>" --rel-b "<label>", never by
hand-editing the related: array or the Relationships/See Also bullets.
Use a typed relationship label rather than a generic one. The label is free text as far as the
tool is concerned - it is written into a - **label:** [[Title]] bullet and no code matches on
it - so which vocabulary this instance uses is
kb/CONVENTIONS.md § Relationship labels's to list.
A page is expected to have at least one inbound link; wikitool lint reports orphans.
Comparison pages are exempt - they are reached through the catalog.
Renaming a page, deleting one, or dropping a single reference are tool operations with their own procedure: see 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), ormixed(both; put the unsourced part under a## General Guidance (unsourced)heading).raw_files:on every source page - concrete existing file paths underraw/, never a directory and never a bare URL. For an external article also setsource_url:, butraw_files:must still point at the local copy underraw/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), and addsSource - Xtosources:- 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 lintchecks 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 syncreconciles 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,Cadds 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 coveragelists 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'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 lint reports - they are written to
reports/and are not pages. - Answers with no source behind them.