Files
chemenu/docs/language-boundaries.md
T
torben 6eb3f84256
CI / verify (push) Failing after 38s
docs: README-Typenbaum und language-boundaries auf den guidance-Split nachgezogen (#104)
Files changed:
- README.md
- docs/language-boundaries.md
2026-09-15 18:25:18 +02:00

136 lines
8.5 KiB
Markdown

# Language Boundaries
Two languages run through this repo at once. `kb/` is written in whatever language the instance
chose - German here, and the value lives in `kb/CONVENTIONS.md`'s `language:`. Everything that
tells an agent what to do - [AGENTS.md](../AGENTS.md), every `CONTRACT.md`, everything under
`instructions/` - is written in English, in every instance, whatever the first value says.
The rule itself is in [AGENTS.md § File naming](../AGENTS.md#file-naming). This page holds the
part that is not a rule: why the line runs where it does, why the English half is not a setting,
and which argument for it turned out to be wrong.
<!-- wikitool:toc -->
## Contents
- [The axis is the reader, not the owner](#the-axis-is-the-reader-not-the-owner)
- [Why the control plane's language is English](#why-the-control-planes-language-is-english)
- [Why it is not a parameter](#why-it-is-not-a-parameter)
- [What the KB language still decides](#what-the-kb-language-still-decides)
- [Where the line runs around a page type](#where-the-line-runs-around-a-page-type)
- [What would put this back on the table](#what-would-put-this-back-on-the-table)
<!-- /wikitool:toc -->
## The axis is the reader, not the owner
For a long time the two halves could be told apart by asking who owned the file, and the answer
came out right every time: the stack owns `AGENTS.md` and the contracts, which are English; the
instance owns its pages and the templates that shape them, which are in the KB language. The
ownership boundary is a real and load-bearing thing - [ownership-and-templates.md](ownership-and-templates.md)
is about what it buys - so it was easy to read the language split as one of its consequences.
It is not. The case that separates them is a page type an instance adds for itself. `types/`
takes a new type without a code change, so an instance can write one; that file is instance-owned
from the first line to the last, ships nowhere, and is nobody's to overwrite. Its authoring
guidance is still instruction addressed to an agent, and reads exactly like the guidance in the
four types the stack ships. Ownership says "yours"; the audience has not moved at all.
So the question a line answers is not *whose file is this* but *who reads this line*, which is
the same cut [kb/CONTRACT.md](../kb/CONTRACT.md#language-and-identifiers) already makes inside a
single page between prose and identifiers - applied one level up, to the halves of a document.
Ownership decides who may change a sentence. The reader decides what language it is in. The two
questions were answered together for as long as they happened to agree.
## Why the control plane's language is English
Not because English is better for the purpose, and not to be neutral: this instance's operator
reads German, and the pages are German for that reason.
- **The control plane is almost entirely about identifiers, and the identifiers are English.**
`base_dir`, `provenance: sourced`, `--confirm`, exit 42, `root: kb`. A sentence in another
language explaining when to set `page_ref_fields` is already half English by the time it
reaches the verb, and the prose/identifier boundary inside it becomes something a reader has to
work out line by line.
- **It quotes a body of material that is English and stays English.** The harness documentation
it has to agree with, the vendored skill-authoring sources under `commonplace/`, the tool's own
`--help`. A contract that translates their vocabulary makes its own claims harder to check
against them, not easier.
- **One language keeps instances comparable.** Two instances running the same stack version hold
the same control plane byte for byte, so a question about one is answerable from the other -
and anything an instance changes locally shows up as a difference in content rather than in
language.
## Why it is not a parameter
The natural next move, once `kb/CONVENTIONS.md` holds `language:`, is a second value beside it -
`control_plane_language:` - defaulting to English and settable by an instance that would rather
read its contracts in its own language. That option is deliberately not taken.
- **The knob's cost is paid by every file; its benefit lands on the few a human reads.** Every
rule about writing an instruction would have to name which of the two languages it means, every
example would need a note saying which one it is in, and every review of an instruction would
start by establishing which language it should have been in. The stack has one mechanism for
that class of problem - one rule, one place (AGENTS.md invariant 8) - and a second language
value forks it everywhere at once.
- **The document the knob is for is read by an agent.** An instruction, a contract, a type-spec's
guidance half: the reader is a model, and a model reads the English fine. What the *operator*
reads is unaffected by any of this - see the section below.
- **Today's local document is tomorrow's upstream candidate.** An instruction an instance wrote
for itself is the most likely thing it ever contributes back. Written in the KB language it
would have to be translated first, and the translation would have to re-derive the
prose/identifier boundary that the original author had in their head and did not write down.
- **Nothing would check it.** There is no mechanical test for what language a paragraph is in -
a stop-word scan flags the quoted vocabulary the rule deliberately keeps and misses a cleanly
translated paragraph. A setting nothing enforces produces drift that is visible only to whoever
next opens the file.
## What the KB language still decides
Making the control plane English does not make the instance's language an implementation detail.
`kb/CONVENTIONS.md`'s `language:` decides two things, and both are the ones an operator actually
experiences:
- **Page text.** Every page under `kb/`, and inside the page type-specs exactly the parts that
become page text - each one's `## Template` block and its `layout:` titles.
- **What an agent says.** An agent speaks the KB language, whatever the file it just read was
written in. An instruction that models a sentence for the operator writes that model in
English, like the rest of the control plane, and the agent delivers it in the instance's
language.
So an operator who reads no English gets German pages and German answers from an agent reading
English instructions. The English is what the machinery is written in, not what it says back.
## Where the line runs around a page type
A page type's contract is where the two languages meet most closely, and it is worth knowing
which part is which before editing any of it. Its authoring guidance addresses an agent and is
English; its `## Template` block and `layout:` titles become the literal headings of pages and
follow the KB language; its field names and enum values are identifiers and are translated in
neither direction.
The language line did not move when the *file* line did. A `root: kb` type-spec may now put its
authoring guidance in a separate, stack-owned `types/<name>.guidance.md` rather than carrying it
beside the template, but that split was made for ownership reasons - so an upgrade can improve
the guidance without overwriting what the instance chose - and it leaves this page's argument
untouched: each part is still written in the language its own reader needs, and a type-spec that
declares no `guidance:` keeps both halves in one file with exactly the same rule applying inside
it. [types/type-spec.md § Who owns a type-spec](../types/type-spec.md#who-owns-a-type-spec) has
the split as a table, and [ownership-and-templates.md](ownership-and-templates.md) § "Where the
file boundary used to strain" has what it cost to keep two audiences in one file for as long as
it did.
## What would put this back on the table
A `docs/` page goes stale when the reasoning stops holding rather than when the code changes, so
it is worth naming what that would look like here. Two things would:
- **A human starts reading the control plane directly and routinely** - not an operator checking
a rule now and then, which is the case today, but a workflow where people rather than agents
are the primary readers of `instructions/`. The second argument above is the one that fails
first, and it is the load-bearing one.
- **The identifiers stop being English.** If the tool's own vocabulary were ever localized, the
first argument would invert: the prose would then be the only English left in a file that is
otherwise not, which is the situation this page argues against.
Neither is close. Both are cheaper to notice here than to rediscover in an argument about a
single file.