A tiny, deterministic application kernel for local-first apps — event-log, schema migrations, undo/redo & offline outbox with zero dependencies.
Building Local-First applications (where user data lives on the client device rather than a remote cloud server) is the future of software sovereignty. But managing local state brings severe engineering headaches:
- 💥 Schema Drift: A user has 8 months of data stored locally in SQLite or AsyncStorage. When you push an app update, how do you migrate their schema safely without wiping their data?
- ↩️ Accidental Wipes: Users tap "Delete" or "Cooked" by mistake. Without an event journal, recovery is impossible.
- 📶 Offline Mutations: When the device is offline, mutations must queue in an optimistic outbox and sync gracefully when reconnected.
local-first-kernel solves this as a lightweight, zero-dependency mathematical state kernel:
[ User Intent ]
↓
[ dispatch(type, payload) ]
↓
┌──────────────────────────────────────────────┐
│ LOCAL-FIRST KERNEL │
│ │
│ ├── EventLog (Append-only journal) │
│ ├── Reducer (Deterministic state math) │
│ ├── UndoStack (Time-travel history) │
│ ├── OutboxQueue (Offline sync queue) │
│ └── Migrations (Zero-data-loss versioning) │
└──────────────────────────────────────────────┘
↓
[ Verified Local State (SQLite / AsyncStorage) ]
npm install @rynia/local-first-kernelimport { LocalKernel } from '@rynia/local-first-kernel';
interface PantryState {
items: Array<{ id: string; name: string; qty: number }>;
}
const kernel = new LocalKernel<PantryState>({
schemaVersion: 1,
initialState: { items: [] },
enableUndo: true,
reducer: (state, event) => {
switch (event.type) {
case 'item.added':
return { items: [...state.items, event.payload] };
case 'item.removed':
return { items: state.items.filter(i => i.id !== event.payload.id) };
default:
return state;
}
}
});
// Dispatch deterministic events
kernel.dispatch('item.added', { id: '01', name: 'Organic Honey', qty: 1 });
kernel.dispatch('item.added', { id: '02', name: 'Sourdough Bread', qty: 2 });
console.log(kernel.getState());
// => { items: [ { id: '01', name: 'Organic Honey', qty: 1 }, ... ] }// Undo the last action
kernel.undo();
console.log(kernel.getState().items.length); // => 1
// Redo it back
kernel.redo();
console.log(kernel.getState().items.length); // => 2When your app evolves from v1 to v2 (e.g. adding a mandatory category field to items):
const v2Kernel = new LocalKernel({
schemaVersion: 2,
initialState: { items: [] },
reducer: (state, event) => state,
migrations: [
{
fromVersion: 1,
toVersion: 2,
migrate: (oldState) => ({
items: oldState.items.map(item => ({
...item,
category: item.category || 'Pantry Default'
}))
})
}
]
});
// Import old v1 snapshot from device storage:
// Kernel automatically runs migration pipeline from v1 to v2 safely!
v2Kernel.importSnapshot(oldV1Snapshot);// Every mutation automatically enqueues into kernel.outbox
console.log(kernel.outbox.size); // => 2 pending actions
// When internet is restored:
const pending = kernel.outbox.getPending();
for (const item of pending) {
// Sync to peer / backup server:
await syncToServer(item.event);
kernel.outbox.markSynced(item.id);
}local-first-kernel powers the state, undo guard, and inventory telemetry of KALANLA (Kiler Kitchen OS).
Part of the deterministic, local-first engineering suite crafted by @Rynia:
| Package / Project | Role | Version |
|---|---|---|
| local-first-kernel | Append-only reactive event micro-kernel & offline sync | v1.0.0 |
| expo-release-guard | Pre-flight zero-rejection store compliance & privacy manifest CLI | v1.0.0 |
| receipt-renderer | Zero-dependency 9:16 thermal receipt AST & dual SVG/ASCII renderer | v1.0.0 |
| KALANLA | Smart kitchen pantry OS powered by this ecosystem | Live Beta |
See CHANGELOG.md for detailed version history and architectural notes.
- License: MIT © 2026 Muharrem Özmen (@Rynia)
- Architected by: Rynia Studios
- Part of the Rynia Local-First & Ambient Systems initiative.