APP DEFINITION LANGUAGE

App DSL

34 lines of JSON define an entire encrypted application. RBAC, encryption, UI, and E2E tests — all derived from a single declaration.

34Lines
5Apps
6Derived Blocks
1:683Code Ratio

Scope

An app.enc.json file is a minimal JSON declaration that a transpiler reads to derive all Lean spec blocks for a complete ENC application. Four top-level fields — data, ui, test, and encryption — define the event schema, RBAC rules, screen layout, and end-to-end test plan. The transpiler (gen_from_enc.py) produces Lean spec blocks that are byte-identical to the hand-written originals.

Here is the complete Chat application — 34 lines:

chat.enc.json34 lines
{
  "app": "Chat",
  "encryption": "mls",
  "color": "#10b981",

  "data": {
    "Message":  "Member CR",
    "Reaction": "Member C",
    "Profile":  "Member C",
    "Topic":    "Admin C",
    "Read":     "Member C",
    "Grant":    "Owner C -> Admin Member",
    "Revoke":   "Owner C -> Admin Member"
  },

  "ui": [
    "groups    | tab default | list groups",
    "compose   | tab         | form group-name member-key -> create",
    "group/:id |             | thread messages -> send Message",
    "profile   | tab         | form display-name bio -> save Profile"
  ],

  "test": [
    "alice creates group 'Alices Group' with [bob, charlie]",
    "alice creates group 'Bobs Group' with [bob]",
    "alice sends 'Hello everyone!' in 'Alices Group'",
    "bob sends 'Hey Alice! Bob here.' in 'Alices Group'",
    "charlie sends 'Charlie checking in!' in 'Alices Group'",
    "alice sends 'Welcome!' in 'Bobs Group'",
    "bob sends 'Thanks!' in 'Bobs Group'",
    "---",
    "alice sees 2 groups",
    "alice opens 'Alices Group' sees ['Hello everyone', 'Bob here', 'Charlie']",
    "alice sends 'From UI!' in 'Alices Group'",
    "alice opens 'Bobs Group' sees ['Welcome', 'Thanks']",
    "alice sends 'Also from UI!' in 'Bobs Group'",
    "alice opens groups sees 2 groups",
    "alice opens profile",
    "alice cycles [groups, compose, profile]"
  ]
}

From this single file, the pipeline derives the RBAC schema, role bitmasks, manifest constructor, content validators, frontend routes, mobile screens, service SDK, test contracts, and E2E test flows — across Lean, TypeScript, React, and React Native.


Top-level Fields

FieldTypeRequiredDescription
appstringyesDisplay name ("Chat", "DM", "Timeline")
encryptionstringyes"none" | "ecdh" | "mls"
colorstringyesPrimary color hex ("#10b981")
dataobjectyesEvent type to role shorthand map (the RBAC schema)
uistring[]yesPipe-delimited screen definitions
teststring[]yesNatural language test steps, "---" separates setup from validation

Optional fields include roles (explicit role list), endpoints (dev server ports), react (React vs vanilla DOM), and includes (composition from other apps).


Data Schema

The "data" field maps event type names to role shorthand strings. Each entry compiles to an RBAC schema rule with event type, role, and permitted operations.

Shorthand Format

Syntax
// Basic: role + operations
"EventType": "Role Ops"

// With targets: for Grant/Revoke
"EventType": "Role Ops -> TargetRole1 TargetRole2"

Parsing Rules

ShorthandExpanded
"Member CR"{event: "Message", role: "Member", ops: ["C", "R"]}
"Owner C -> Admin Member"{event: "Grant", role: "Owner", ops: ["C"], target_roles: ["Admin", "Member"]}
"Self CR"{event: "Sent", role: "Self", ops: ["C", "R"]}
"Any R"{event: "*", role: "Any", ops: ["R"]}

Valid operations: C (Create), R (Read), U (Update), D (Delete), P (Push).

Special Event Names

NameMeaning
*Wildcard — applies to all event types
GrantRole grant operation (has target_roles)
RevokeRole revoke operation (has target_roles)
Grant_PushGrant + webhook push registration (has target_roles)

Special Role Names

RoleMeaning
SelfAuthor of the event (own events only)
AnyAny identity (no role required)
OwnerEnclave owner
DataViewData view service role

UI Definition

The "ui" array defines screens as pipe-delimited strings. Each line produces a route, a view file, a mount function, testIDs, and both web and mobile screen shells.

Grammar

Format
route | [tab [default]] | elements

Element Types

ElementSyntaxProduces
Listlist XFlatList/scroll with testID X
Formform field1 field2 -> actionTextInput(s) + submit button
Threadthread X -> send EventTypeMessage list + compose input + send button
Toggletoggle [a, b]Segmented control switching between views
Showshow fieldRead-only display field
Detaildetail field1 field2Detail view with labeled fields
Actionsactions like commentAction buttons (appended to detail)

Examples

UI Lines
// Tab with default list view
"groups    | tab default | list groups"

// Form with two fields and a submit action
"compose   | tab         | form group-name member-key -> create"

// Thread view (messages + send)
"group/:id |             | thread messages -> send Message"

// Search with toggle
"search    | tab         | form search | toggle [nodes, identities]"

// Detail with action buttons
"post/:id  |             | detail post comments | actions like comment"

// Settings (read-only display)
"settings  | tab         | show dataview-url"

Derived Names

From each screen key the transpiler auto-derives:


Test Definition

The "test" array contains natural language steps that compile into structured E2E test flows. A "---" separator divides SDK-level setup from UI-level validation.

Test Structure
"test": [
  // ── SDK setup (runs via SDK, no UI) ──
  "alice creates group 'Alices Group' with [bob, charlie]",
  "alice sends 'Hello everyone!' in 'Alices Group'",
  "bob sends 'Hey Alice!' in 'Alices Group'",
  "---",
  // ── UI validation (runs against rendered app) ──
  "alice sees 2 groups",
  "alice opens 'Alices Group' sees ['Hello everyone', 'Hey Alice']",
  "alice cycles [groups, compose, profile]"
]

Setup Patterns

PatternAction
alice creates group 'X' with [bob, charlie]createGroup
alice sends 'Hello!' in 'X'sendGroupMessage
alice sends 'Hello!' to bobsendDM
alice requests bobsendRequest
bob accepts aliceacceptRequest
alice posts 'Hello world!'post
alice likes bob postlike
alice comments 'Great!' on bob postcomment
alice follows bobfollow
alice sets profile name='Alice' bio='Tester'setProfile
sdk registers N nodessdkRegister

Validation Patterns

PatternAction
alice sees N groupsassertGroupCount
alice opens 'X' sees ['a', 'b']openAndValidate
alice sends 'X' in 'Y' via UIsendGroupMessage (UI)
alice opens profile sees 'Alice'openScreenAndValidate
alice opens friends sees [bob, charlie]openScreenAndValidate
alice cycles [tab1, tab2, tab3]navCycle
alice opens node detail sees [pubkey, endpoint]openDetailAndValidate
alice opens search searches nodesearchFor
alice registers node via UIregisterViaUI

Encryption Levels

The "encryption" field selects one of three levels, each adding cryptographic capabilities to the generated wallet, session, and middleware:

LevelValueWalletSessionMiddleware
L0"none"Extension + devmode, simple signingSHA256 challengeNone
L1"ecdh"+ persistent ECDH keypair, local signingBIP-340 taggedHash, eagerECDH key exchange
L2"mls"+ grant tracking, identity sessionBIP-340 taggedHash, deferredMLS group key management
Encryption is structural. The same JSON shape produces a plaintext app at L0 or a fully end-to-end encrypted group chat at L2. Only the "encryption" field changes.

Derived Blocks

The transpiler generates six Lean spec blocks from each app.enc.json:

F

@frontend

Web route definitions, endpoint URLs, middleware type. Drives config.js, router.js, wallet.js.

M

@mobile

Expo Router tabs, screens, onboarding config. Drives the React Native app scaffold.

S

@service

SDK operations, signing config, identity storage. Drives the service module shared by web and mobile.

C

@test_contract

Per-screen element contracts — testIDs for lists, inputs, buttons, text. Auto-derived from ui.

T

@test_flow

Structured E2E test actions parsed from natural language test steps.

A

@app_schema

RBAC schema, role bitmasks, manifest constructor, content validators. The data backbone.


Pipeline

The JSON definition flows through a multi-stage pipeline, producing artifacts at each layer:

app.enc.json gen_from_enc.py App.lean + Frontend.lean
Lean specs gen_mobile.py Expo Router app
Lean specs gen_frontend.py Vite SPA
Lean specs gen_test_contract.py + gen_test_flow.py E2E tests

The amplification ratio is dramatic:

Layer           Lines    Ratio
-----           -----    -----
JSON input      34       1
Lean specs      306      9
TypeScript out  23,222   683
                -----
                1 : 9 : 683

34 lines of JSON produce 306 lines of Lean spec which generate 23,222 lines of TypeScript — screens, service modules, test contracts, and E2E workflows. The developer writes JSON. The pipeline writes everything else.


All Apps

Five applications are defined with app.enc.json, spanning all three encryption levels:

AppEncryptionColorData EventsUI ScreensTest Steps
Registry none #5b5bd6 4 6 11
Timeline none #1d9bf0 8 7 13
DM ecdh #10b981 7 5 14
Chat mls #10b981 7 4 16
Messenger mls #50e3c2 composed 12 19
Messenger is a composition app — it includes DM, Chat, and Timeline via the "includes" field. Its data schema is merged from the constituent apps; routes, tests, and service blocks are defined independently.

ENC PROTOCOL · APP DSL · 34 LINES · 5 APPS · 1:683 RATIO