SPEC-DRIVEN DEVELOPMENT

ENC Protocol

34 lines of JSON define an entire encrypted application. A transpiler derives Lean specs, the compiler validates, codegen produces web + mobile + E2E tests. Code ratio: JSON 1 : Lean 9 : TypeScript 683.

34Lines JSON
5Apps
1:683Code Ratio
162Theorems
0%Flake Rate

Spec-Driven Development (SDD)

34 lines of JSON define an entire encrypted application. A transpiler derives Lean specs, the Lean compiler validates, and codegen scripts produce web + React Native mobile + E2E tests. The human writes a declaration. Math does the rest.

Human writes app.enc.json (34 lines per app)
    │
    │  gen_from_enc.py (transpiler)
    
Lean 4 formal spec (~300 lines, compiler-verified)
    │
    │  yarn build:ts (6 codegen scripts)
    
Full-stack application
    + TypeScript web frontend (Vite SPA)
    + React Native mobile (Expo Router + WDK wallet)
    + E2E tests (web + RNW + Waydroid, shared workflow)
    + Code ratio: JSON 1 : Lean 9 : TypeScript 683
Traditional (vibe coding)ENC (SDD)
AI → code → human reads it → debugHuman → 34 lines JSON → transpiler → Lean → compiler validates → ship
Hours and days (human bottleneck)Seconds (compiler bottleneck)
Hope it works162 theorems checked by Lean's kernel
$50K-$500K security auditFormal proofs, zero audit cost
Code is the artifactMath is the artifact, code is a derivative
Rewrite everything for mobileSame JSON → web + mobile + tests from one command
Flaky E2E tests (text matching)__test_state bridge + testID: 0% flake rate

Traditional development requires a human verification layer: read generated code, understand it, test it, debug it. SDD removes the human from the loop. The Lean compiler validates the derived specs. Codegen is deterministic. Same input always produces the same output. The question isn't "how do we help AI write better code?" — it's "why is anyone writing code at all?"

Implementation is a derivative — a by-product of the mathematical specification, generated on the fly. 34 lines of JSON produce ~300 lines of Lean, which produce ~23,000 lines of TypeScript. The code has no independent existence. Change the JSON, re-derive the spec, regenerate the app.

34
Lines JSON
app.enc.json — sole authoring surface
5
Apps
Chat, DM, Timeline, Registry, Messenger
1:683
Code ratio
JSON 1 : Lean 9 : TypeScript 683
66
Lean files
14,869 lines — compiler-verified
162
Theorems
SMT, RBAC, crypto, state transitions
0%
Flake rate
__test_state + testID convention

Build any app from JSON

1. Write apps/your-app.enc.json (34 lines)
     app, encryption, color, data, ui, test

2. gen_from_enc.py (transpiler)
      App.lean        (schema, event types, RBAC)
      Frontend.lean   (@frontend, @mobile, @service, @test_contract, @test_flow)

3. yarn build:ts (6 codegen scripts)
     gen_mobile.py           Expo Router app (WDK wallet + screens)
     gen_service_mobile.py   service layer
     gen_test_contract.py    testID constants
     gen_test_flow.py        E2E workflow
     gen_frontend.py         Vite SPA
     gen_js.py               backend (Cloudflare DO + Worker + SDK)

4. Ship.
      No handwritten code beyond 34 lines JSON
      Web + mobile + tests from one command
      All 5 apps byte-identical from transpiler

Architecture

Seven layers. Each composes from the ones below. No cycles.

7Codegen Targets595 lines · 3 files
Server.lean · Client.lean · Frontend.lean
Three duals. Three IO boundaries. Three faithful functors.
6Bridge + UI DSL967 lines · 2 files
Bridge.lean (theory ↔ protocol) · Frontend/ (Lean Component Architecture)
5Typeclasses + Composition1,215 lines · 3 files
App/Typeclasses · App/Instances · Composition
6 typeclasses × 4 instances, 43 composition theorems
4Applications7,182 lines · 19 files
Registry · Timeline · DM · Chat · Messenger
(App, SDK, DataView, State, Components) per app
3Middleware361 lines · 2 files
ECDH (1-to-1 encryption) · MLS (group encryption)
2Core Protocol3,361 lines · 22 files
Primitives · SMT · CT · Event · RBAC · Validation · Node · SDK
1FTA (Formal Theory)946 lines · 12 files
Primitives · Identity · Trust · Secrecy · State · Storage
Binding · Transition · View · Effect · Application · Theorems

Documents

Each layer has a corresponding specification document.

DocumentLayerWhat it specifies
fta.md1Formal theory: primitives, axioms, 48 theorem obligations
enc.md2Protocol: crypto, events, RBAC, validation, node, SDK
middleware.md3Encryption: ECDH (1-to-1 DM) + Lazy MLS (group chat)
server.md4Server: Enclave → Runtime → Service → Cloudflare DO
client.md5Client: Enclave → ClientRuntime → Client → JS SDK
web.md6Frontend: AppView → FrontendRuntime → React web
native.md6Native: AppView → same specs → React Native mobile
overview.mdThis document

Supporting references:

node-api.mdxHTTP/WebSocket API reference (endpoints, auth, errors)
proof.mdxProof wire formats (SMT, CT, Bundle)
smt.mdxSparse Merkle Tree specification
spec.mdxLegacy specification (superseded by fta.md + enc.md)

The Three Duals

One pattern applied three times. Each layer is a composition of a spec type with an IO boundary, yielding a codegen target.

LayerSpec typeIO boundaryCompositionJS target
ServerEnclaveRuntime (12)ServiceCloudflare DO
ClientEnclave (same)ClientRuntime (10)ClientSDK
FrontendAppViewFrontendRuntime (8)FrontendReact app

The client does not define its own type. ClientView = Enclave. The server’s Enclave is the single source of truth for routes, reads, encryption, and schema. The client just reads it from a different perspective.

Enclave = {
  schema       extraRoutes   encrypted
     │              │             │
     ├──Server──────┤             │
     │  allRoutes   │             │
     │  ddl         │             │
     │  handlers    │             │
     │              │             │
     ├──Client──────┤─────────────┤reads       │  encrypt?   │
     │  writes      │             │
     │  protocol    │             │
     │              │             │
     └──Frontend────┤StateFns    │  wiring     │
        Components  │             │

Information Flow

Information is defined once and flows downward. No re-specification.

fta.md   App.render : S → V                    pure function (Theorem 45)├─ enc.md   AppManifest.schema               event types + RBAC rules
  │    │
  │    ├─ enc.md   AppSDK W constructors       17 write operations
  │    │    │
  │    │    └─ proven: all reduce to createCommit (Theorem 42)
  │    │
  │    └─ enc.md   Middleware (ECDH/MLS)        encryption parameters├─ server.md   Enclave                       7 fields, SINGLE SOURCE
  │    │
  │    ├─ Enclave.allRoutes                     derived (protocol + extra)
  │    ├─ Enclave.ddl                           derived (hasDataView?)
  │    └─ Enclave.reads                         derived (GET from extraRoutes)├─ client.md   ClientView = Enclave           ZERO new fields
  │    │
  │    ├─ Client.write  = AppSDK.buildCommit    from enc.md
  │    ├─ Client.read   = Enclave.reads         from server.md
  │    └─ Client.query  = protocolRoutes        shared└─ web.md   AppView = (Enclave, AppDef, CSSApp)├─ Components     from @component specs (44 components, 3,904 lines React)
       ├─ Handlers        SDKFunc  Client.write
       ├─ Effects         StateFn  Client.read
       └─ CSS            from Theme.lean + app stylesheets (100% coverage)

Trust Boundaries

37 axiomatized IO methods across three runtimes. Everything else is derived, proven, or structurally enforced.

BoundaryMethodsImplementationLines JS
Runtime12Cloudflare DO API~50
ClientRuntime10fetch + WebSocket~30
FrontendRuntime8useReducer + Cmd214
Crypto7noble-curves~10
Total37~110

Cryptographic axioms (standard hardness assumptions):

sha256_collision_resistanceif SHA-256 is secure
schnorr_correctnessBIP-340
ecdh_symmetricCDH assumption
encrypt_roundtripXChaCha20Poly1305 AEAD
hkdf_one_waynessrandom oracle model

These are not implementation trust — they are mathematical assumptions the entire field relies on.


Theorem Summary

162 theorems across all layers.

LayerTheoremsKey results
Theory10FTA meta-theorems
Core20SMT soundness, CT inclusion, expiry rejection
Middleware1ECDH roundtrip
Apps65Schema well-formedness, SDK reductions
Typeclasses1Complete witness existence
Composition43C1-C6 composition conditions (all 4 apps)
Bridge348 FTA theorem witnesses
Server15Route counts, capability matrix, DDL
Client4Read counts, no-DV-no-reads

Notable proofs:


Codegen Pipeline

The codegen pipeline is a faithful functor from Lean definitions to JavaScript artifacts. “Faithful” means structure-preserving: one output per input, no creative decisions.

Server codegen

Enclave                   one DO class
Enclave.allRoutes         Worker route dispatch
Enclave.ddl               DO constructor (SQL CREATE TABLE)
Runtime (12 methods)      ~50 lines JS (Cloudflare DO API)
Service (4 entry points)  DO class (constructor, fetch, webSocketMessage, alarm)

Client codegen

AppSDK W constructors     sdk.createPost(text), sdk.like(id), ...
Enclave.reads             sdk.getFeed(opts), sdk.getProfile(id), ...
protocolRoutes            sdk.query(filter), sdk.getSTH(), ...
ClientRuntime             fetch() / WebSocket (trusted FFI)
Enclave.encrypted         encrypt/decrypt wiring (conditional)

Frontend codegen (Lean Component Architecture)

@component.state            useReducer init state
@component.messages         { type, payload } union
@component.update           (state, msg) → [state, Cmd]  (pure function)
@component.view             JSX tree
@component.subscriptions    WebSocket event handlers
@component.initCmd          initial data fetch
@elements (Elements.lean)   inlined icons, helpers, shared elements
@css (Theme.lean)           generated-supplement.css
@component (all)            auto-generated test files (gen_tests.py)

Trust boundary: runtime.ts (214 lines) — Cmd executor only. gen_react.py generates 44 components (3,904 lines React).


The Four Applications

RegistryTimelineChatDM
schemastaticstaticstaticstatic
addressingsingletonper-userper-groupper-pair
DataView
Push✗*
Bootstrap
encrypted✗*
middlewarenonenoneMLSECDH
reads (GET)5700
writes3752
components7987

*enc-node handles push and transport encryption for DM.

Messenger (13 components) composes DM + Chat + Timeline at the frontend layer, importing their SDKs and states.


File Map

66 Lean files organized by layer.

Enc/── Theory/                          Layer 1: FTA (946 lines)
│   ├── Primitives.lean                Val, Key, Time, CryptoSuite
│   ├── Identity.lean                  Id (Anon|Hold|Share|Attest)
│   ├── Trust.lean                     Schema, Origin, Op
│   ├── Secrecy.lean                   Scheme (Direct|Tree), Transport
│   ├── State.lean                     Life, Persist
│   ├── Storage.lean                   Store, Atomicity, Interface
│   ├── Binding.lean                   Trigger, BindMode, Binding
│   ├── Transition.lean                Action (set|del|bind)
│   ├── View.lean                      V (el|text|empty)
│   ├── Effect.lean                    Effect (fetch|open|close|...)
│   ├── Application.lean               FTA.App typeclass (48 obligations)
│   └── Theorems.lean                  FTA meta-theorems
│
├── Core/                            Layer 2: Protocol (3,361 lines)
│   ├── Primitives/                    Types, Crypto, Hash, SMTKey
│   ├── SMT.lean                       Sparse Merkle Tree
│   ├── CT.lean                        Certificate Transparency
│   ├── Event/                         Types, Commit, Lifecycle
│   ├── RBAC.lean                      Schema, permits, Grant/Revoke
│   ├── Validation.lean                14-step commit pipeline
│   ├── Node.lean                      NodeState, processCommit
│   ├── SDK.lean                       createCommit, verify*, encrypt*
│   │   └── Client.lean                SessionManager, NodeClient, WS
│   ├── Handlers.lean                  Route dispatch, SQL type
│   ├── Persistence.lean               NODE_TABLES_DDL
│   ├── Push.lean                      P/N delivery, retry backoff
│   ├── WSHandlers.lean                WebSocket message handling
│   ├── DataView.lean                  SYNC_STATE_DDL, event indexing
│   └── Migration.lean                 Enclave migration protocol
│
├── Middleware/                      Layer 3: Encryption (361 lines)
│   ├── ECDH.lean                      1-to-1 (DM): agree, encrypt, decrypt
│   └── MLS.lean                       Group (Chat): epochs, fwd secrecy
│
├── Apps/                            Layer 4: Applications (7,182 lines)
│   ├── Registry/                      Discovery service
│   │   ├── App.lean                     Schema (3 event types)
│   │   ├── SDK.lean                     3 writes
│   │   ├── DataView.lean                NodeIndex, EnclaveIndex, REST
│   │   ├── State.lean                   AppState + 4 component states
│   │   └── Components.lean              8 components (520 lines)
│   ├── Timeline/                      Public microblog
│   │   ├── App.lean                     Schema (7 event types)
│   │   ├── SDK.lean                     7 writes
│   │   ├── DataView.lean                PostIndex, ProfileIndex, REST
│   │   ├── State.lean                   AppState + 7 component states
│   │   └── Components.lean              12 components (1,049 lines)
│   ├── DM/                            Encrypted messaging (ECDH)
│   │   ├── App.lean                     Schema (3 event types)
│   │   ├── SDK.lean                     2 writes
│   │   ├── State.lean                   AppState + 5 component states
│   │   └── Components.lean              9 components (810 lines)
│   ├── Chat/                          Group chat (MLS)
│   │   ├── App.lean                     Schema (5 event types)
│   │   ├── SDK.lean                     5 writes
│   │   ├── State.lean                   AppState + 4 component states
│   │   └── Components.lean              9 components (868 lines)
│   └── Messenger/                     Composed (DM + Chat + Timeline)
│       └── Components.lean              20 components (2,038 lines)
│
├── App/                             Layer 5: Typeclasses (693 lines)
│   ├── Typeclasses.lean                6 typeclasses + ENCApp witness
│   └── Instances.lean                  4 × 6 instances, 17 proofs
│
├── Bridge.lean                      Layer 6: Theory ↔ Protocol (508 lines)
├── Frontend/                        Layer 6: Lean Component Architecture── Composition.lean                 Layer 5: C1-C6 theorems (522 lines)
│
├── Server.lean                      Layer 7: Server codegen (281 lines)
├── Client.lean                      Layer 7: Client codegen (134 lines)
└── Frontend.lean                    Layer 7: Frontend codegen (180 lines)

Reading Order

For understanding the protocol:

  1. fta.md — the abstract theory (what any app must satisfy)
  2. enc.md — the concrete instantiation (how ENC satisfies it)
  3. server.md — the backend (four services from one Enclave type)
  4. client.md — the SDK (dual of server, zero new types)
  5. web.md — the UI (@component → useReducer + Cmd → React)

For understanding the Lean code:

  1. Enc/Theory/Application.lean — the FTA.App typeclass
  2. Enc/Core/Node.lean — the Node (ordering authority)
  3. Enc/App/Instances.lean — how apps satisfy the typeclasses
  4. Enc/Server.lean — the Enclave (single source of truth)
  5. Enc/Client.lean — the dual (ClientView = Enclave)
  6. Enc/Frontend/ — the Lean Component Architecture (Cmd, Component, Elements, CSS)

One Sentence

The ENC protocol is seven composable layers — from abstract math to React components — where a single Enclave structure determines the complete server, SDK, and frontend for any application, with 162 theorems proving the pipeline preserves correctness at every stage.