005 — Repository Language
Everything committed to this repository is in English. The only exception is a tenant's own configuration, which is gitignored and never committed.
This is not a translation task
The Spanish currently in src/ is a symptom, not the problem. Customer-facing copy is hardcoded in source:
// src/routes/turn.ts
const ACK_MESSAGE = 'Dame un segundo que lo chequeo 👍';
// src/agent/guardrails.ts
const ESCALATION_TEXT = 'Dejame que te pase con alguien del equipo...';Translating those to English produces the same bug in a different language: a codebase that can serve exactly one linguistic market, now English instead of Spanish. A tenant in São Paulo would be equally stuck.
So the rule is stronger than "write English". It is:
No customer-facing natural language lives in source at all. Copy belongs to the tenant, in configuration. Source contains English identifiers, comments, and documentation — and no sentences a contact could ever read.
That makes the repository publishable in English and makes the product multi-tenant in a way it currently is not.
The four categories
| Category | Rule |
|---|---|
| Code, comments, identifiers, docs, specs, ADRs, commit and PR text | English, always |
| Customer-facing copy (acknowledgement, escalation message) | Not in source — tenant config |
| Prompt scaffolding the framework owns (operating rules, catalogue labels) | English; never reaches a contact verbatim |
| A tenant's persona, catalogue, and reply language | Tenant config, any language, gitignored |
Reply language is configuration, not a property of the code
The framework's prompt scaffolding is English. The tenant's persona file states the language and register to answer in. Models follow a persona instruction to reply in another language reliably, so English scaffolding does not force English replies — it only stops the framework from assuming a language it has no business assuming.
This is already how config/prompt.md works. The change is that the rest of the prompt stops being Spanish too.
What changes
1. Copy moves to rules.json
ESCALATION_TEXT and ACK_MESSAGE become tenant-configured, with the schema requiring them. No default is shipped in source: a missing value must fail at boot rather than silently emitting English at a Spanish-speaking contact.
{
"messages": {
"acknowledgement": "Give me one second while I check.",
"escalation": "Let me put you through to someone on the team.",
},
}2. prompt.ts scaffolding becomes English
Operating rules, the security preamble, the format instructions, and the catalogue labels (descripcion: → description:, cursada: → schedule:). These are internal structure; a contact never sees them.
Escalation reason identifiers (price_negotiation, complaint) are already English and stay exactly as they are — they are enum values, not prose.
3. The committed demo tenant becomes English
config/*.example and test/fixtures/config/* describe a fictional English-speaking academy. These are the first thing a stranger reads, and a Spanish demo in an English repository reads as an oversight.
4. Tests and evals become English
Test names, assertions, and fixture strings. evals/golden/cases.jsonl becomes English cases against the English demo catalogue.
Tests contain no non-English prose either, including fixtures and test data.
That still leaves the guarantee testable. What must be proven is that copy comes from configuration, not that any particular language works — so the suite runs the same code paths for two tenants whose copy differs, both in English. If a string were baked back into source, both tenants would receive it and the assertions fail. Two English tenants prove that exactly as strongly as an English and a non-English pair, without putting prose into the repository that C9 forbids.
The alternate tenant's persona asks for replies in another language — written in English, as an instruction — which is where a real tenant expresses that, and it is carried through verbatim without the framework interpreting it.
The exception, scoped precisely
A deploying tenant's real config/prompt.md, config/catalog.json, config/rules.json and .env stay in whatever language that tenant sells in. They are gitignored (Constitution C1) and verified unstageable. The exception needs no discipline to hold — git enforces it.
Order of work
- Copy out of source (
guardrails.ts,turn.ts, schema, config examples). This is the behavioural change and the only one that can break a running bot, so it lands first and alone. - Prompt scaffolding (
prompt.ts) — re-run the eval suite after, since prompt wording changes model behaviour and that is what the evals exist for. - Demo tenant and fixtures.
- Tests and evals, including the non-English section.
mock-provider.tsreplies, last — it is test infrastructure and changing it early would obscure whether step 2 altered real behaviour.
Verification
pnpm evalpasses against the English demo tenant, and the non-English section passes against its fixture. Step 2 is the risk: if English scaffolding degrades escalation accuracy, the evals are what will show it.A test asserts that no file under
src/contains non-ASCII Latin letters (\u00C0-\u024F). Accented characters are the cheap signal that prose in another language has been pasted back in.This is a heuristic, not language detection: it catches accented prose and misses unaccented prose. It exists to catch the obvious regression, not to be authoritative. Review is the real enforcement.
No file under
config/other than*.exampleandREADME.mdis tracked.