A native shell that downloads its apps.
Jinnie is a super app: a native host that owns the binary and every native dependency, and thirteen mini apps that arrive as separate bundles fetched at runtime. One shared SDK is the same object inside all of them, which is what lets a bill paid in one app show up in another.
The three layers
| Layer | Owns |
|---|---|
| Host shell | The binary, every native dependency, navigation, Home, the launcher, the tab bar, and the remote wiring. |
| SDK and bridge | The bridge contract, the platform stores, the public catalogs, the UI kit, and the icon set. |
| Mini apps | One screen each. No native modules. Thirteen ship today. |
Why the SDK is one object
Every mini app declares React, React Native, and the SDK as shared singletons. For React that is the usual reason: two copies crash. For the SDK the reason is the product. The Wallet ledger is a store inside the SDK. A second copy of the SDK would mean a second ledger, and Bills would post payments that Wallet never sees. The host loads the shared modules eagerly; mini apps do not, so they resolve the host’s copies instead of bundling their own.
Core and community
Every app manifest declares a kind. Core apps are first-party and receive the finance context, meaning the active accounts, the ledger, and the four mutations that change it, while community apps receive none of that and get key-value storage namespaced to their own id instead. The check lives in one place, the bridge provider, so it isn't a matter of folder layout or good manners; the context is simply never handed over.
Data
- Offline-first. Every store persists on the device under its own key. The shell holds the splash until every store has been read, so no screen renders a zero balance that then jumps.
- One money context. Transfers carry source and destination without changing cash-flow totals. Bill payments carry bill and period ids so Wallet edits and deletions reconcile Bills. Reversal is exact: overdrafts and liability credits are negative balances, never silently clamped.
- Account lifecycle. Only active accounts cross the bridge. Archived accounts stay in local history and can be restored.
- Portable backup. Settings exports every record as one JSON file and restores from one, validating product, schema version, namespace, size, dates, and value types before writing, and snapshotting current data first so a failed restore rolls back.
Failure is a normal state
Because a mini app is fetched over the network, “didn't load” is an ordinary outcome rather than an exception, and each app renders inside its own error boundary with a retry button. An unreachable origin or a bad bundle costs you one broken tab, never the shell. The federation runtime is reset for that one remote before the retry, so the second attempt is a real fetch and not a replay of the first failure.
Releases
Publishing a new bundle for a mini app updates it for existing installs without an app-store release. The host binary changes only when a native dependency or the registry does. That is the cost the architecture is designed to make visible.
Building one? The SDK guide covers the package, the bridge, the catalogs, and the rules.