For AI coding agents

Where the change goes.

Humans ask when architecture is unclear. Agents infer and continue. So this page states where things go rather than describing qualities to aim for — and the repository's AGENTS.md is the machine-readable version of it.

Governance

Three systems, three questions.

They do not overlap. When one answers, the others do not override it.

Who governs what when an agent changes this repository
SystemGovernsWhat it asks of you
Ordo / SDEEngineering legality and evidenceKnow the current state, the legal transition, and the evidence required before you change anything. The installed method is in .sde/.
Praxis / ROSWork lifecycle and attributionStart a work item before editing and complete it with real evidence. CI rejects changes no work item accounts for.
LimenArchitectural placementPut each change in the one layer allowed to own it. The rest of this page is that rule.

Contract and guardrails

Do not widen the boundary to finish a task.

If an implementation is hard, that is not permission to weaken a rule.

Rules

  • One language-neutral contract is the source of truth. No guest language is canonical.
  • Generated contract code is read-only output: regenerate it, never hand-edit it.
  • No handwritten parallel wire types beside generated ones.
  • No untyped escape hatch at the boundary: no any, dynamic, object bag, or string-typed operation.
  • Feature work never weakens the guardrail that is blocking it. A wrong guardrail is changed in its own work item, with evidence.
  • Every task declares its architectural placement and stays inside that scope.
  • Compiler enforcement differs by language — F# unions, Rust enums, C# generated closed types with analyzers — but each maps the same neutral contract.
  • If the architecture blocks the work, create an explicit work item. Do not broaden the boundary quietly.

Status on main

Implemented today: engine-purity checks (scripts/check-architecture.ts), F# builds with warnings as errors, and work-item attribution in CI.

Accepted and in progress: the neutral contract source and generated bindings (#52), dependency and path-scope checks (#53), the restricted TypeScript subset (#54), C# and Rust guest enforcement (#55).

Until generation lands, src/protocol.ts is the contract and this site’s F# engine mirrors it by hand. That mirror is the known exception to the no-parallel-types rule, not a pattern to copy.

The guardrail specification (#51) →

Contract

Ten rules, all MUST.

Violating one is a defect regardless of whether tests pass.

Before you change anything

Read the boundary first.

The architecture here is unusual, and code that looks reasonable by mainstream front-end conventions is often wrong. The single most useful file is the protocol — about eighty lines, and it is the architecture.

The boundary, in detail →

  1. 01
    Authoritative application state lives in the engine, nowhere else
  2. 02
    Do not introduce application state in JavaScript outside the engine
  3. 03
    Browser events enter only through data-event and the kernel
  4. 04
    Validation, legality and what-to-show are engine decisions
  5. 05
    Browser capabilities are reached only through an effect request
  6. 06
    HTML stays structural; CSS stays presentational
  7. 07
    The kernel stays generic — never branch on domain meaning in it
  8. 08
    All four HTTP outcomes are represented; OutcomeUnknown is not a failure
  9. 08b
    A browser-initiated navigation is adopted, never answered with another push
  10. 09
    Existing public contracts are preserved
  11. 10
    The repository's full check passes before you are done

Routing

The decision tree.

Most ambiguity resolves in the first three branches.

I need to add behavior.
│
├─ Is it purely visual (color, spacing, motion, hover)?
│  └─ YES → CSS. Stop. Do not route it through the engine.
│
├─ Is it document structure (an element, a label, a landmark)?
│  └─ YES → HTML. Add data-* only if the engine must drive it.
│
├─ Does it decide, validate, remember, or compute anything
│  about the application?
│  └─ YES → the engine. Add a state, a command, a transition,
│            and a projected key.
│
├─ Does it need HTTP, local storage, the clipboard, or the
│  browser’s history?
│  └─ YES → the engine returns an EffectRequest. It does NOT
│            call fetch, navigator.clipboard or history.pushState.
│
├─ Is it what a URL MEANS?
│  └─ YES → the engine. The kernel splits a URL into
│            path/query/hash and stops.
│
├─ Did the browser move on its own (Back, Forward)?
│  └─ YES → adopt the location. Request NOTHING: pushing again
│            traps the user on the page.
│
├─ Does it need a browser capability that does not exist yet
│  (files, timers, focus, clipboard read)?
│  └─ YES → a protocol extension. A bigger change: propose it,
│            do not slip it in.
│
└─ Am I about to hold application state in JavaScript,
   outside the engine?
   └─ STOP. That is rule 1. Go back to the third branch.

The test that resolves most cases in one line: would the application behave differently because of this? Yes means the engine. No means HTML or CSS. “Which tab is showing” passes that test — it changes what is legal and what matters, so it is application state. “What color the active tab is” fails it, so it is CSS.

Try it on eight real tasks: Demo 04 on the demos page.

Recognition

Stop if you are writing these.

Each is a boundary breaking, not a shortcut.

Signals that a change is going in the wrong layer
You are writingThe problem
document.querySelector outside the kernelReading the DOM as truth
fetch( in the engineA hidden effect — and the build will fail
let currentX in page JavaScriptA second state store
switch (event.name) in the kernelThe kernel learning domain meaning
innerHTML, or markup in a template stringMarkup generated by application logic
.classList.add to reflect application stateA capability re-derived in the DOM
setTimeout to “wait for” a projectionRacing the round trip
case "Failure": case "OutcomeUnknown": togetherConflating two genuinely different outcomes
An array index as a list keyUnstable identity; focus and input land on the wrong row

Checklist

Before and after.

Answer 1–8 before writing; confirm 9–13 before finishing.

Before

  1. What state changes? Which union member, in which state type?
  2. What event causes it, and from which element?
  3. Is the transition legal from every state it can be requested in? What happens when it is not?
  4. Is an external effect required, and of which kind?
  5. Who performs it? (The answer is: the kernel.)
  6. How does the result return, and how is a stale one rejected?
  7. Which projected keys change? Are capabilities projected explicitly?
  8. What HTML or CSS is needed? (Usually: none.)

After

  1. Am I creating duplicate state anywhere?
  2. Am I adding application logic outside the engine?
  3. Am I bypassing a boundary for convenience?
  4. What tests prove this — including the illegal case and the stale result?
  5. Does the full repository check pass?

This repository also enforces a work-item protocol in CI. Open one before editing, or the pull request is rejected regardless of whether the code is correct — see AGENTS.md.

If the documentation does not cover your case

Reason from the boundary, in order.

And if you conclude the architecture itself is the obstacle, say so explicitly and record it. Do not route around it silently — that is the one failure mode this design is least tolerant of.

AGENTS.md — the full entry point →

  1. 01
    Does this decide anything about the application? → the engine
  2. 02
    Does this touch the outside world? → an effect request; if no capability exists, it is a protocol change
  3. 03
    Is this about how something looks? → CSS
  4. 04
    Is this about what something is? → HTML
  5. 05
    Still unsure? → ask. Do not infer a new mechanism and continue.
  6. 06
    Blocked by the architecture? → record a work item. Do not weaken the check.