Pure C → WASM. Nous wire protocol for everything. Vanilla HTML/JS. Zero frameworks. Ship to phones.
Updated after comparison with NOUS Desktop → Pantheon decoupling plan.
Build bahalaka as a sovereign relationship platform where every byte of data flows through the nous wire protocol (NTRP0001) via nous relay servers. No Firebase. No REST APIs. No HTTP to the catalog-server. No third-party backends. One channel, one protocol, one door. Every feature is atoms packed by wire.c, encrypted by crypt.c, routed through relay_server.c. The C stack is the app.
The NOUS Desktop → Pantheon tool decoupling follows the exact same pattern we're using. Their approach:
sdk/ folder. Self-contained. No dependency on the full nous tree.relay_client.c packs triples, encrypts with cockpit key, sends to relay, decrypts response. All backend communication through the relay. No direct calls to catalog-server.receive_loop_json_buf() directly, they now pack {loop, action, none} + {question, content, none} triples, encrypt, send to relay. The relay forwards to the intelligence engine and returns the result.bahalaka follows this exact pattern. The only difference: browser clients need WebSocket (they can't do raw TCP), and bahalaka introduces new atom verbs that need handlers on the prime.
Chat message? Atom through the relay. Status update? Atom through the relay. Financial transaction? Atom through the relay. Agreement signature? Atom through the relay. Comment on the proposal? Atom through the relay. There is no other path.
The relay is already the authenticated gateway. Auth, encryption, and routing are already solved. Adding HTTP to the catalog-server would mean a second auth path, a second transport, and a second attack surface. Wire keeps it to one channel — one key, one protocol, one door.
This is the same reasoning the NOUS Desktop plan uses. It works. Don't add doors.
{subject, predicate, object} — every piece of data is a triplewire.c → compiled to WASM, runs client-side in the browsercrypt.c → AES-256-GCM per atom, Ed25519 signaturessdk/: wire.c, crypt.c, aes_gcm.c, sha256.c, pack.c, journal.c, store.c, policy.c + their headers.libbahalaka.wasm via Emscripten. Self-contained — no dependency on the full nous tree. All atom packing, all crypto, all local storage happens in C. JS never touches a key, never packs an atom.bahalaka.js (~500 LOC) — the browser equivalent of NOUS Desktop's relay_client.c.bahalaka.send(verb, data) → WASM packs atom → encrypts → returns binary → JS sends over WebSocket.bahalaka.recv(binary) → WASM decrypts → unpacks atom → returns JS object → UI renders.relay_client.c — pack triples, encrypt, send to relay, decrypt response.webDir: 'app' points to the same folder.bahalaka.com/ → proposal site (live now, stays) bahalaka.com/app/ → the web app (one URL, works everywhere) bahalaka.com/app/get/ → smart download page (auto-detects OS)
/app/ — The web app. Same HTML/JS/WASM on every device. Also the PWA fallback./app/get/ — Auto-detects Android/iOS/desktop. Shows the right store button. One link to share./app/ locally. Never loads from URL. Runs offline.bahalaka/
index.html ← proposal site (existing)
be/ ← Be artifacts
app/
index.html ← web app shell (loads WASM + bridge)
bahalaka.js ← JS bridge / relay client
bahalaka.conf.js ← config: relay host, relay port, key paths
libbahalaka.wasm ← C→WASM binary
libbahalaka.js ← Emscripten glue
pages/
login.html ← TOTP auth
chat.html ← forward-only messaging
status.html ← GPS-verified presence
schedule.html ← calendar + time requests
finances.html ← allowance + ledger + sponsorships
agreements.html ← templates + dual signing
stories.html ← field guide
settings.html ← preferences + connections
css/
app.css ← dark theme, mobile-first
get/
index.html ← smart download page
sdk/
wire.c / wire.h ← vendored from nous
crypt.c / crypt.h ← vendored from nous
aes_gcm.c / aes_gcm.h ← vendored from nous
sha256.c / sha256.h ← vendored from nous
pack.c / pack.h ← vendored from nous
journal.c / journal.h ← vendored from nous
store.c / store.h ← vendored from nous
policy.c / policy.h ← vendored from nous
Makefile ← Emscripten build: sdk/ → libbahalaka.wasm
Same approach as NOUS Desktop. Copy the self-contained C modules from C:\kastil\nous into sdk/. These modules have zero nous-internal dependencies — they're pure data transforms, pure crypto, pure storage. No #includes reaching back into the nous tree.
wire.c/h — NTRP0001 atom pack/unpack (pure data transform, no I/O)crypt.c/h — Ed25519, AES-256-GCM, SHA-256 (no platform deps)aes_gcm.c/h + sha256.c/h — crypto primitivespack.c/h — binary packing helpersjournal.c/h — append-only log (I/O shimmed to IndexedDB via Emscripten IDBFS)store.c/h — triple store for local offline cache (I/O shimmed to IDBFS)policy.c/h — client-side rule enforcementThe Makefile compiles sdk/*.c → app/libbahalaka.wasm + app/libbahalaka.js. No Emscripten reaches outside sdk/.
Same pattern as NOUS Desktop's desktop.conf. All connection parameters in one file. No hardcoded relay addresses.
const BAHALAKA_CONFIG = {
relay_host: 'relay-us.3-nous.net',
relay_port: 8443,
relay_ws_path: '/ws',
key_storage: 'indexeddb', // where Ed25519 keys live
offline_journal: 'indexeddb', // local journal backing
version: '2.0'
};
The bridge reads this at startup. WebSocket connects to wss://{relay_host}:{relay_port}{relay_ws_path}. One channel. One config.
Each triple is an atom packed by wire.c, encrypted by crypt.c, sent through relay. Forward-only — no delete. Edits create new triples preserving the original.
GPS auto-matches registered locations via Capacitor. Status transitions are atoms through the relay, journal-logged on prime.
Request → approve/decline. All atoms through the relay. Prime enforces isolation — connection A never sees connection B's schedule.
Balance = computed sum of all disbursement + withdrawal triples on prime. No mutable balance field. The ledger is the truth. Every transaction is a signed atom through the relay.
3-part template system: Her Ask (7) + His Declaration Part 1 (7) + Part 2 (3) = 147 combinations. Dual Ed25519 signatures, 48-hour cooling period enforced by timestamp math. All atoms through the relay.
reason.c walks the triple graph on prime, counts patterns, scores confidence. 7 signal types: promise ratio, request frequency, status anomalies, edit frequency, response asymmetry, schedule conflicts, financial patterns. Results pushed to provider as atoms through the relay.
Proposal site comments migrate from Firestore REST API to nous triples. Same UI, same UX — different backend. Comments become atoms through the relay like everything else.
All sources vendored into sdk/. Emscripten compiles only from that folder.
wire.c — NTRP0001 atom pack/unpack. The protocol runs in the browser.crypt.c — Ed25519 keypair/sign/verify, AES-256-GCM encrypt/decrypt, SHA-256aes_gcm.c + sha256.c — crypto primitivespack.c — binary packing helpersjournal.c — local append-only log (IndexedDB backing via Emscripten IDBFS)store.c — local triple store for offline cache (IndexedDB backing)policy.c — client-side rule enforcement (cooling periods, forward-only checks)Output: app/libbahalaka.wasm + app/libbahalaka.js (Emscripten glue)
Exports: wire_pack, wire_unpack, crypt_encrypt, crypt_decrypt, crypt_sign, crypt_verify, crypt_keypair, journal_append, store_insert, store_query
relay_server.c — WebSocket + TCP forwarder. Authenticates. Never decrypts. Routes atoms by session.catalog_server.c — prime. Receives atoms via relay, routes by verb. Stores triples. Runs reason.c.reason.c — concern detection. Walks the full triple graph. Needs all user data. Server-only.auth.c — session management, TOTP verification, nonce ring. Server-only.audit_engine.c — tamper detection, pattern analysis. Server-only.relay_server.c currently speaks raw TCP (NTRP0001 binary frames). Browser clients can't do raw TCP — they need WebSocket. Add RFC 6455 handshake + frame decode/encode as a transport layer. The NTRP0001 atoms ride inside WebSocket frames. Same protocol, different transport.
NOUS Desktop connects via raw TCP (native C binary). bahalaka connects via WebSocket (browser). Both send the same atoms to the same relay. The relay doesn't care which transport delivered them.
Firewall: Open WebSocket port on relay VMs (Virginia, London, Singapore).
The prime already receives atoms from the relay, decrypts them, and routes by content. It already handles store queries and intelligence requests — that's how NOUS Desktop works today.
For bahalaka, we register new atom verb handlers on the prime. Not an HTTP endpoint. Not a new service. Just new verbs that the existing atom routing processes:
chat — store message triples in sender + recipient storesstatus — store/query status triples with isolation enforcementschedule — store/query time request triplesfinance — store financial triples, compute balances from journal sumsagree — store agreement triples, enforce cooling period timestampsdeclare — store promise/commitment triples with deadline trackingconcern — trigger/query reason.c pattern walksstory — query curated content triplesEach verb handler operates on per-user encrypted stores at /data/bahalaka/{user_id}/. store.c already supports different paths — just a new directory per user. Encrypted at rest with AES-256-GCM. WAL journaled.
Atoms arrive through the relay the same way NOUS Desktop's intelligence queries do. Same channel. Same auth. Same encryption. New verbs.
Vendor the SDK. Prove C runs in the browser. Set up the app folder. Build the bridge.
sdk/ — copy wire.c, crypt.c, aes_gcm.c, sha256.c, pack.c, journal.c, store.c, policy.c + headers/app/ folder structure (shell, pages, CSS, config)sdk/*.c → app/libbahalaka.wasmbahalaka.js bridge / relay client: keypair generation, sign/verify, encrypt/decrypt, atom pack/unpack, WebSocket managementbahalaka.conf.js: relay host, port, WS pathjournal.c + store.c I/O shimmed to Emscripten IDBFS for local persistenceTwo server-side changes. User registration. Connection pairing. All via atoms through relay.
relay_server.c (RFC 6455 handshake, frame decode/encode)/data/bahalaka/{user_id}/)Forward-only messaging. The core use case. Everything over wire protocol through relay.
read and typing atom verbs through relayAsymmetric visibility. Geo-verified presence. Calendar as atoms through relay.
{user, status, location_type} packed by wire.c, sent through relay, prime stores via status verb handlerAllowance, savings, sponsorships. Every transaction a signed atom through the relay.
Templates, promises, dual signatures, concern detection. The crown jewel.
policy.c (client WASM) checks her_ask vs his_dec before signing atom sentreason.c walks on prime — promise ratio, request frequency, status anomalies, edit frequency, response asymmetry, schedule conflicts, financial patternsField guide. Onboarding. App stores. Friends-first launch.
/app/get/ — auto-detects OS, links to store/app/ foldersdk/. No dependency on the full nous tree. Self-contained build.sdk/, outputs .wasm + glue .js.webDir: 'app' + native project scaffolding.