Plan — bahalaka Complete App (v2)

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.

Intent

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.

Proven Pattern — NOUS Desktop

Same Architecture, Already Working

The NOUS Desktop → Pantheon tool decoupling follows the exact same pattern we're using. Their approach:

  1. Vendor the C SDK — copy the minimum required sources (wire.c, crypt.c, http.c, pack.c) into an sdk/ folder. Self-contained. No dependency on the full nous tree.
  2. Create a relay clientrelay_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.
  3. Replace in-process calls with wire requests — where they used to call 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.
  4. Zero backend changes — the desktop tool adapts to the existing relay/wire API surface. kastil-systems/nous stays as-is.

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.

The One Rule

Everything Is an Atom Through the Relay

User action JS event bahalaka.js WASM (wire.c packs atom) WASM (crypt.c encrypts)
WebSocket relay (forwards, never reads) prime (routes by atom verb)
prime unpacks stores as triples responds via same path

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.

Why Wire, Not HTTP

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.

NTRP0001 Wire Protocol

Architecture

Four Layers

Server Side (Already Running)

URL Structure

Three URLs, One Codebase

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)

Folder Structure

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

SDK Vendor Strategy

Copy the Minimum, Cut the Cord

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.

The Makefile compiles sdk/*.capp/libbahalaka.wasm + app/libbahalaka.js. No Emscripten reaches outside sdk/.

Configuration

bahalaka.conf.js

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.

Data Model — Everything as Triples via Wire Protocol

Chat

{msg:a1b2, from, user:joey} {msg:a1b2, to, user:maria} {msg:a1b2, text, "kumusta ka?"} {msg:a1b2, time, 1712345678} {msg:a1b2, sig, ed25519:abc123...}

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.

Status

{user:maria, status, at_home} {user:maria, status_time, 1712345678} {user:maria, location:home, geo:14.5995,120.9842}

GPS auto-matches registered locations via Capacitor. Status transitions are atoms through the relay, journal-logged on prime.

Schedule

{timereq:001, from, user:maria} {timereq:001, to, user:joey} {timereq:001, slot, 2026-04-05T18:00} {timereq:001, status, pending}

Request → approve/decline. All atoms through the relay. Prime enforces isolation — connection A never sees connection B's schedule.

Finances

{allowance:001, recipient, user:maria} {allowance:001, amount, 5000} {allowance:001, cycle, weekly} {disbursement:042, allowance, allowance:001} {disbursement:042, net, 4000} {disbursement:042, sig, ed25519:def456...}

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.

Agreements

{agree:001, her_ask, template:1} {agree:001, his_dec_1, template:III} {agree:001, his_dec_2, template:A} {agree:001, sig_her, ed25519:aaa...} {agree:001, sig_him, ed25519:bbb...} {agree:001, cooling_start, 1712259278}

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.

Concern Detection — reason.c

{concern:c01, type, promise_ratio} {concern:c01, user, user:maria} {concern:c01, kept, 2} {concern:c01, total, 6} {concern:c01, confidence, 0.78}

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.

Comments (Migration)

{comment:c01, section, 3} {comment:c01, author, "Joey"} {comment:c01, text, "this is fire"} {comment:c01, time, 1712345678}

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.

C → WASM Strategy

What Compiles to WASM (Client-Side)

All sources vendored into sdk/. Emscripten compiles only from that folder.

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

What Stays Server-Side C

Server-Side Changes (2 Total)

1. WebSocket Transport on Relay

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).

2. Bahalaka Atom Verb Handlers on Prime

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:

Each 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.

Build Phases

Phase 1 — WASM Foundation

Vendor the SDK. Prove C runs in the browser. Set up the app folder. Build the bridge.

Phase 2 — Server Infra + Registration

Two server-side changes. User registration. Connection pairing. All via atoms through relay.

Phase 3 — Chat

Forward-only messaging. The core use case. Everything over wire protocol through relay.

Phase 4 — Status + Schedule

Asymmetric visibility. Geo-verified presence. Calendar as atoms through relay.

Phase 5 — Finances

Allowance, savings, sponsorships. Every transaction a signed atom through the relay.

Phase 6 — Agreements + Trust

Templates, promises, dual signatures, concern detection. The crown jewel.

Phase 7 — Stories + Ship

Field guide. Onboarding. App stores. Friends-first launch.

What Dies

Killed

Constraints

Summary

What This Is