nomos_flutter 0.27.1
nomos_flutter: ^0.27.1 copied to clipboard
Drive the real Nomos GitHolon from a Flutter app — a local-first domain runtime. iOS runs the native-AOT kernel (no WebView memory cap); Android/macOS use a hidden secure WebView. Write TypeScript dom [...]
nomos_flutter #
Drive the real Nomos GitHolon from a Flutter app. You write a powerful, polymorphic TypeScript domain,
run nomos compile, and get a typesafe Dart client. This package is the runtime that client runs on: it
boots the byte-identical wasm32-wasip1 GitHolon inside a hidden, secure WebView host and hands you a
connected bridge. TS domains in, Flutter widgets out — the webview embedding, the secure loopback origin,
the runner bundle, the wasm, and sync are all hidden in here.
Local-first: every read, write, and merge happens on-device against the local holon; the cloud is custody + sync. One binary on web/iOS/Android/macOS.
Use it #
# pubspec.yaml
dependencies:
nomos_flutter: ^0.1.0
import 'package:flutter/material.dart';
import 'package:nomos_flutter/nomos_flutter.dart';
import 'nomos/todo.client.dart'; // generated by `nomos compile` (copy build/dart/ into your app)
void main() => runApp(const MaterialApp(home: Home()));
class Home extends StatelessWidget {
const Home({super.key, required this.uid, required this.token});
final String uid; // the signed-in user's auth-provider uid (e.g. Supabase / Firebase)
final String token; // their access token (sent as x-nomos-auth, kernel-verified)
@override
Widget build(BuildContext context) => NomosScope(
cloud: 'https://nomos.captainapp.co.uk',
workspace: homeNameOf('user:$uid'), // the user's OWN home holon (see "Auth + home" below)
authToken: token, // proves who they are — required for private/home data
builder: (context, nomos) {
final app = TodoClient(nomos.bridge); // your generated typed client
return TodoPage(app); // app.addTodo(...), app.watchTodosByList(...)
},
);
}
That's the whole integration. NomosScope boots the holon, connects to the workspace, and rebuilds with a
connected NomosClient; everything platform-specific is inside the package.
A public, shared workspace (a guestbook, a demo) can pass a fixed
workspace: 'my-workspace'and omitauthToken. But a per-user app should address the user's OWN workspace by identity and authenticate — see Auth + home holons below.
Auth + home holons #
Nomos identity comes from YOUR auth provider (Supabase, Firebase, Auth0 — any OIDC-style issuer the cloud
or your platform trusts). A request proves who it is by sending its access token as x-nomos-auth;
NomosScope does that for you when you pass authToken:
final session = Supabase.instance.client.auth.currentSession; // your provider's SDK
NomosScope(
cloud: 'https://nomos.captainapp.co.uk',
workspace: homeNameOf('user:${session!.user.id}'),
authToken: session.accessToken, // → x-nomos-auth: <token>, verified IN the kernel
builder: (context, nomos) => YourPage(nomos.bridge),
);
The token is verified by the githolon itself (ES256-via-JWKS, or the legacy HS256 lane) — the host
verifies nothing. An invalid token is REFUSED; if you omit authToken, the request rides the open
anonymous lane (fine for public reads, but private/home data fails closed without a principal).
(Transitional bare-uid lane: a backend that already trusts the caller can send the raw uid as
x-nomos-principal instead — there is no NomosScope field for it; it's a raw-HTTP detail.)
What a home holon is #
A home holon is the workspace that belongs to ONE identity — a user's personal, subject-side root. "Workspace", "platform", and "home" are the SAME githolon wearing the role its installed law gives it; a home runs the identity law (its public device-key directory, a "shared-with-me" index, and an inbox of grants/invites/notifications). Private keys never leave the device, so the cloud hosting it stays operator-blind.
A home is addressed by a DETERMINISTIC, collision-free name derived from the identity's SUBJECT — never the raw uid and never an app-chosen string — so the same principal always resolves the same home, on every peer and on the cloud, and a share addressed to a subject routes to exactly ONE home:
// homeNameOf(subject) == 'home-' + first 40 hex chars of sha256(utf8(subject))
final ws = homeNameOf('user:$uid'); // e.g. 'home-9f86d081884c7d659a2feaa0...'
homeNameOf is exported from package:nomos_flutter/nomos_flutter.dart (and from @githolon/client in
JS, and the law side in dsl/src/framework/home.ts) — all three are byte-identical, and the home's own
law carries a "squat" invariant that asserts its name hashes its owner, so a workspace named home-<h> can
only ever be its rightful owner's slot. Use it directly as the workspace. A home is born lazily — a share
can be delivered to a stranger's home before they ever log in.
The typed client #
nomos compile emits build/dart/<name>.client.dart (+ <name>.dart) — a <Domain>Client over a
NomosBridge with typed dispatch, reactive watch… queries parsed into read models, by-id reads, and O(1)
count/sum. You wrap it over nomos.bridge:
final app = TodoClient(nomos.bridge);
final head = await app.addTodo(AddTodoPayload(listId: id, text: 'milk')); // offline-first write
app.watchTodosByList(listId: id).listen((rows) => setState(() => _todos = rows)); // reactive read
await nomos.bridge.sync(); // push session branch → cloud admission → pull main
Platform setup #
Almost nothing — but Apple's sandbox needs one line that a package cannot set for you:
- macOS: add to
macos/Runner/DebugProfile.entitlementsandRelease.entitlements:
(The sandbox blocks even the loopback host without it.)<key>com.apple.security.network.client</key> <true/> - iOS / Android / Web: nothing. (iOS loopback is exempt from Local Network privacy; web uses the page origin.)
How it works (so you don't have to think about it) #
The holon is JavaScript+wasm; Flutter can't run it directly. NomosScope mounts a 1×1 flutter_inappwebview
and serves the bundled runner over a loopback http://127.0.0.1 origin — a secure context, so
crypto.subtle + storage + WebAssembly all work (an about:blank/file: origin silently breaks them). The
runner boots @githolon/client, which pulls the byte-identical holon wasm + the workspace ledger from the
cloud and replays it locally. A small JSON bridge connects Dart ↔ the runner. flutter_inappwebview is used
(not the official webview_flutter) because its WKWebView embedding is the robust one across macOS/iOS.
Platform setup (Firebase auth + home holons + estate invitations) #
If you are standing up a product on a Nomos platform (e.g. co2): the full step-by-step — set Firebase BYOAuth, give each user a home holon, birth estate workspaces, and the free SharedWithMe invitation system — is in architecture/co2_platform_runbook.md. Every step is proof-backed (bench/scale/home_delivery_e2e.mjs).