Language-neutral WASM application authority · explicit browser boundary
Make the browser a mechanism, not a second application.
Limen gives the browser a narrow job: carry semantic events, apply a projection, and perform explicit effects. Authoritative application state and meaning live behind a WebAssembly boundary, in an engine that owns the state, legal transitions, capabilities, obligations, and interpretation of evidence.
This website’s reference engine is F# compiled to .NET WebAssembly. The boundary itself is language-neutral: the same contract is intended for C#, Rust, and other strongly modelled WASM engines.
This site is a consumer of Limen, not a mockup of it.
- application state: WASM engine
- this site’s engine: F#/.NET
- browser authority: Limen
- markup: static HTML
Why the boundary exists
Hard UI problems are usually authority problems.
The issue is not whether JavaScript can update a span. It can.
Legality
Can this action happen now?
Release approval depends on evidence. Deployment depends on approval. A disabled button should reflect that decision, not make it.
Evidence
Is this response still current?
Two requests overlap. The older response arrives last. Without correlation and explicit state, stale evidence silently wins.
External effects
Did the write fail, or do we not know?
A timeout after dispatch is not failure. Treating it as failure and retrying blindly is how duplicate effects are created.
Placement
Which layer is allowed to decide?
HTTP is browser mechanism. Interpreting 409 is application meaning. Focus control is not currently a Limen capability. Those distinctions are the architecture.
Framework flexibility versus architectural constraint
Fewer legal places for behavior to live.
React and Angular make the right thing convenient. Limen’s goal is to make the wrong thing structurally difficult.
Powerful frameworks
Many ways to build it
React and Angular are mature and capable. They give teams flexible mechanisms and let each team assemble its own architecture.
Constrained architecture
One place for meaning
Limen fixes where application meaning, browser mechanism, appearance, and structure go, so a misplaced decision is visibly wrong.
Enforcement
Checked, not just advised
Types, the protocol, and repository checks reject boundary violations. Some checks run today; more are accepted and in progress.
This is a difference in design goals, not a measured ranking. Why Limen, and where React and Angular are stronger today →
Self-hosting proof
The site follows the architecture it describes.
HTML and CSS remain browser-native. Limen turns interactions into plain messages and performs browser effects. A tiny transport loads the .NET WebAssembly runtime. Every application decision on the interactive pages lives in the F# engine.
The npm package itself is still a TypeScript browser kernel. The F# WASM site engine is a real consumer of that package boundary, not code shipped as part of the kernel.
- 01HTML/CSS define document structure and presentation.
- 02BrowserKernel carries semantic events and applies projections.
- 03WASM transport serializes one message in and one response out.
- 04F# engine owns state, legality, obligations, effects, and view projection.
Live problem
A release is not a collection of booleans.
Resolve evidence, obtain authority, then test what happens when deployment evidence becomes uncertain.
Release gate
Not startedUnresolved work
No retry button. The request timed out after dispatch. The effect may already exist.
The buttons are not the rules. F# projects capabilities such as
canApproveRelease and canDeployRelease from authoritative
state. Limen only applies them to the DOM. A timeout becomes
ReconciliationRequired, which removes deployment capability until new
authoritative evidence arrives.
Why a strongly typed engine
The difficult part becomes ordinary typed code.
The engine never imports a browser API. F# is this site’s reference language; Rust enums and generated C# closed types are the accepted equivalents.
type DeploymentState =
| NotStarted
| InFlight of CorrelationId
| Deployed
| DeploymentFailed of reason: string
| ReconciliationRequired
type ReleaseState = {
Tests: EvidenceState
Security: EvidenceState
Approved: bool
Deployment: DeploymentState
}
await new BrowserKernel(
new WasmSiteTransport(),
document,
diagnostics
).start();
// No release state.
// No approval rule.
// No retry policy.
What follows from the boundary
Structural consequences, not benchmark claims.
The evidence page separates what is enforced from what remains unmeasured.
Application state has one owner
The WASM engine decides — F# on this site. The DOM is projection output and browser-local state remains browser-local.
Effects are evidence
The browser reports classified outcomes. The engine decides what those outcomes mean to the application.
Capabilities are projected
The UI does not reconstruct permission by peeking at text, CSS classes, or unrelated flags.
The boundary is executable
This site crosses it for real: static HTML → Limen → serialized protocol → F# WebAssembly → projection.
See exactly what is measured, structural, provisional, and still unknown →
Go deeper
Make the hard cases fail in front of you.
Challenge
Interactive engineering cases
Release gating, stale evidence, ambiguous effects, and boundary-placement problems.
Understand
Architecture
What runs in the engine, what stays in the browser, and what the kernel is forbidden to know.
Decide
Why Limen
How Limen differs from React and Angular, and which claims are implemented, accepted, or unmeasured.
Build
For AI agents
A bounded answer to “where does this change belong?”
Reference
Documentation
Protocol, effects, testing, routing, clipboard, troubleshooting, lifecycle CLI.