Design Philosophy
Why is Kumiki shaped the way it is? This page condenses the design rationale — the premises behind the language. For how the 7 layers work in practice, read Thinking in Kumiki; this page is about why they exist at all.
Why not React
React is a human-centered optimum: Hooks, Context, and JSX are idioms refined over nearly twenty years to feel natural to people. As the writer of code shifts to AI, the same machinery becomes friction:
| Friction | What it costs an AI |
|---|---|
| Syntactic overhead | JSX inflates tokens — closing tags, camelCase attributes, expression embedding |
| Implicit side effects | useEffect dependency arrays, stale closures, forgotten cleanup |
| Order-dependent rules | Hooks call order, no Hooks in conditionals or lists |
| Implicit scope | Provider hierarchies, Context resolved invisibly from descendants |
| Non-local rendering | A parent re-render propagates; suppressing it with memo adds complexity |
The pattern: all of these are writable when an AI writes them, and become sharply harder when an AI must fix them or touch them in parallel. When the cause of a bug lives outside the program text — execution history, a dependency array, a stale closure — the AI cannot reason about it without cramming the entire history into its context window.
Kumiki removes this friction structurally, not by convention.
Design requirements
- Token efficiency — the same UI in fewer tokens than React.
- Static traceability of side effects — which effect depends on which state, and where it fires, is evident from the syntax alone.
- Architectural predictability — bugs localize; errors are machine-readable codes.
- Resilience to parallel editing — dozens of agents editing simultaneously must not break the program semantically.
- Readability may be sacrificed — whether humans enjoy reading it is a secondary goal. The primary goal is that AI writes and fixes it accurately.
Requirements 1 and (partially) 2–4 are not aspirations — they are measured continuously. See Benchmarks.
Where four independent designs converged
Kumiki did not start as one design. It started as four independent proposals, each from a separate model-assisted exploration that never saw the others: an S-expression IR with Elm-style actors, an episode-oriented runtime ("Loom"), a one-declaration-per-line effect-typed tile language ("Pyramid"), and a CRDT-native triple-graph ("Nexus").
Comparing them critically revealed that despite entirely different surface syntax, all four converged on the same four cores:
- Side effects are explicit descriptors — pure values, not function calls.
- Local state is prohibited or minimized — every piece of state is statically locatable.
- source ≠ runtime — an IR and a compile step are mandatory.
- An append-only causal log — debugging, replay, and audit share one foundation.
The only remaining disagreement was the physical form of the source text. Kumiki is the hybrid: 7 enforced layers and named slots (Pyramid), capability-bearing effect descriptors (IR+Actor / Pyramid), episode log thinking (Loom), parallel editing as referentially-checked ops (Nexus) — with each proposal's known weakness covered by another's strength (e.g. nesting is allowed only inside tiles, so the one-declaration-per-line shape never degenerates into parenthesis hell or assembly).
Lessons taken from prior art
| Attempt | Adopted | Avoided |
|---|---|---|
| Elm | Complete side-effect isolation; Result/Option | Boilerplate bloat; rigidity of banning local state outright |
| Unison | Content-addressable definitions | Disconnection from the text/Git ecosystem |
| SolidJS | Fine-grained reactivity, compiled dependencies | Hidden tracking scope, signal staleness |
| Hazel / Subtext | Typed holes, zero syntax errors | Input friction |
| Dark | Trace-driven development | Ecosystem lock-in |
| Datomic | Append-only fact log | Unfit for high-frequency updates |
Non-goals
Kumiki deliberately does not aim for:
- Incremental migration of existing React code — zero compatibility; new apps only.
- Comfortable from-scratch authoring by humans — humans can write it; it is not optimized for that.
- Macros, plugins, or language extensions — the AI's learning target stays single and closed.
- Dynamic types — everything is static.
- Multiple rendering targets — DOM only.
Connect at the boundary, never through the language
The non-goals above imply a positive principle: the language itself never grows holes for interop. Connection to the existing JS ecosystem happens at three boundaries, all outside the language:
- Inbound — host code injects implementations for declared capabilities (
mount(app, target, { providers })); standard capabilities likehttp.*can be overridden the same way. See Standard Library §2.5. - Outbound — a Kumiki app embeds into any page as a Web Component (
defineKumikiElement). See Runtime. - Build —
@kumikijs/vitelets any Vite projectimport App from "./app.kumiki", with generated TS types for the providers.
A .kumiki file means the same thing everywhere, because nothing host-specific can leak into it.
The operating model is part of the design
The repository is run on the rule that looking at it resolves every question: questions and bugs are answered by adding working examples and tests, not prose; the spec is normative and every example must compile, build, and survive a smoke test in CI. A language designed for machine consumers needs documentation with the same property — verifiable, not persuasive.
This page summarizes the former design-notes/ directory (removed in #46; design decisions now live in PR descriptions). The full original rationale remains readable in git history.