Reactivity
The SDK ships framework-neutral observables; the binding packages adapt them to each framework's reactivity model.
observe — a field as an observable
import { observe, shallowEqual } from '@atolljs/core';
const metrics = observe(memory, 'metrics');
metrics.get(); // undefined until bound + first write
const unsub = metrics.subscribe(v => render(v));
// Slice form — emits only when the selected slice changes:
observe(memory, 'metrics', m => m.critical);
observe(memory, 'metrics', m => ({ open: m.open }), { equals: shallowEqual });get() stays a stable snapshot between emissions — exactly what useSyncExternalStore-style adapters need. Subscriptions are refcounted: watching starts on first subscriber and stops on last unsubscribe. observe() is bind-safe — it activates when the contract binds on the thread, so SSR and early renders just see undefined.
watch — low-level field watching
import { watch, reactive } from '@atolljs/core';
// Whole field:
const stop = watch(memory.connector('metrics'), (m) => console.log(m.critical));
// Slice + custom equality (mute noise below a threshold):
watch(
memory.connector('latency'),
(v) => v,
(v) => console.log(v),
{ equals: (a, b) => Math.abs(a - b) < 10 }
);
// Signal-tracked reads for solid-js-style effects:
const sig = reactive(memory.connector('metrics')); // sig.get() in effectsdefineTask — async work as observable state
See Worker pool & tasks. Each AsyncTask is an ObservableValue of { data, pending, settled, elapsedMs, error } — the same shape every binding's task adapter consumes.
Logging
import { setLogLevel, setLogSink } from '@atolljs/core';
setLogLevel('debug'); // silent | error | info | debug | trace
setLogSink((entry) => myLogger(entry)); // route SDK logs anywhere