Files
chemenu/kb/CONTRACT.md
T
torben 18ae28f918
CI / verify (push) Failing after 32s
Release / release (push) Successful in 38s
Chemenu 2.1.0 - deterministischer Wissenskompiler
Chemenu kompiliert Rohnotizen zu einem verlinkten, quellengebundenen Wiki:
raw/ -> types/ + tools/ -> kb/ -> reports/. Was mechanisch ist, macht
tools/wikitool; was Urteil braucht, macht ein Agent unter Contracts, deren
Grenzen in Code durchgesetzt sind statt im Prompt.

Dieser Commit ist der Startpunkt der oeffentlichen Historie. Die vorherige
Entwicklung fand in einer privaten Instanz statt und ist nicht Teil dieses
Repositorys; ihre Erzaehlung steht vollstaendig in CHANGES.md, das mit 44
Eintraegen von 0.1.0 bis 2.1.0 erhalten geblieben ist.

Der mitgelieferte Korpus ist ein Testbett und eine Demo: 170 Seiten ueber den
Stack selbst - Gates, Lint, Versionierung, Suche, das Wiki-Muster. Er
dokumentiert das Werkzeug mit den eigenen Mitteln des Werkzeugs.

Lizenz: AGPL-3.0 fuer den Stack (tools/, types/), CC-BY-4.0 fuer die Inhalte.
Die Grenze zwischen beiden ist der Dateiplan, den dist export berechnet -
siehe NOTICE.
2026-09-01 16:26:14 +02:00

13 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. Each kb/<name>/COLLECTION.md declares that it inherits them and adds only what is local to its own subtree - read this file together with the target collection's contract before writing or editing a page.

Structural facts (which frontmatter fields exist, which are required, what the body skeleton looks like) are not here - 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.

  • 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/.
  • 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
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

Adding a collection: mkdir kb/<name> and write a kb/<name>/COLLECTION.md. 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:.

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.

Naming

  • Human-readable titles with spaces: Hybrid Search.md, Gitea Actions.md - not kebab-case.
  • Singular for entities: ha-core.md, not ha-cores.md.
  • Comparison pages read as a comparison: Go vs Rust.md.
  • ADRs are prefixed: adr-001-use-go-modules.md.
  • The filename stem is the page title, and [[wikilinks]] must match it exactly.
  • Prefer readability over convention when the two conflict.

What to name a thing: projects use their repository or common name; systems a descriptive name; tools the tool's own name; technologies their standard spelling and capitalization; people a full name or common handle.

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)

Tone

Wikipedia style: factual, neutral, specific.

  • No buzzwords ("bahnbrechend", "hochmodern", "leistungsstark", "revolutioniert").
  • No AI filler ("es sei angemerkt", "es ist wichtig zu betonen", "in der heutigen Zeit").
  • No em-dash asides carrying parenthetical reasoning.
  • 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.

Good: "MQTT ist ein leichtgewichtiges Publish-Subscribe-Protokoll für Geräte mit knappen Ressourcen."

Bad: "MQTT ist ein bahnbrechendes, hochmodernes Protokoll, das die IoT-Kommunikation revolutioniert - und es sei angemerkt, dass es ein Publish-Subscribe-Muster verwendet."

Language

Pages are written in German. This binds kb/ and the authoring surface that shapes it - the page type-specs types/entity.md, types/concept.md, types/source.md and types/comparison.md. raw/ is untouched (raw/CONTRACT.md), and the control plane stays English: AGENTS.md, the stage contracts including this one, instructions/, and the type-specs for non-page artifacts.

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 Naming. 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

Established English technical terms stay English inside German prose - "GitOps", "Ownership Model", "Reverse Proxy", "Pull Request". Translate a term only where the German one is genuinely the more common usage. A coined German equivalent nobody else writes makes the page harder to find, not more idiomatic.

Which terms those are, which have a settled German form, and the register the prose is written in: instructions/german-terminology.md. It is lookup material, not a second rule - every entry in it is a decision that was made wrong once first.

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 - ## Beziehungen, ## Siehe auch, ## Fußnoten - and tools/chemenu/sections.py is the single place naming them.

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. 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:

hängt ab von · verwendet · implementiert · erweitert · ersetzt · steht in Konflikt mit · benötigt · erzeugt · konsumiert · besitzt · pflegt · läuft auf · verwandt mit (last resort)

The labels are prose written into a - **label:** [[Title]] bullet; no code matches on them, so an untranslated page's English label is stale wording, not a broken reference.

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), 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, 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 Quelle: [^cite-id] line under the block, 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.

Base score for a single source is 0.5, adjusted by:

  • +0.2 per supporting source (max +0.6)
  • +0.2 if confirmed <30 days ago, +0.1 if <90 days
  • +0.1 for official documentation, +0.05 for a reputable secondary source
  • +0.1 if multiple independent sources agree

Re-assess a page with tools/wikitool touch --page "<Title>" --confidence-base <value>.

In prose, hedge according to the score: below 0.6 write "möglicherweise"/"kann"; below 0.4 write "unsicher"/"unbestätigt".

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/.
  • 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.