Reactive Backend
Comparable to: Convex, Firebase, Supabase, Appwrite
Key Concepts
Use the concepts below when they fit the task. Not every reactive backend needs every trigger or realtime surface shown here.
- State is the "database" — CRUD via
state::set,state::get,state::update,state::delete,state::list - State triggers fire automatically when any value in a scope changes
- Side effects (notifications, metrics, stream pushes) are wired reactively, not imperatively
- Streams deliver real-time updates to connected clients
Architecture
HTTP CRUD endpoints
→ `state::set`, `state::update`, `state::delete` (writes to 'todos' scope)
↓ (automatic state triggers)
→ on-change → stream::send (push to clients)
→ update-metrics → state::update (aggregate counters)
HTTP GET /metrics → reads from 'todo-metrics' scope
WebSocket clients ← stream 'todos-live'iii Primitives Used
| Primitive | Purpose |
|---|---|
registerWorker | Initialize the worker and connect to iii |
registerFunction | CRUD handlers and reactive side effects |
trigger({function_id: 'state::...', payload}) | Database layer |
registerTrigger({type: 'state', config: {scope}}) | React to any change in a scope |
trigger({..., action: TriggerAction.Void()}) | Fire-and-forget stream push to clients |
registerTrigger({type: 'http'}) | REST endpoints |
Reference Implementation
See ../references/reactive-backend.js for the full working example — a real-time todo app with CRUD endpoints, automatic change broadcasting via streams, and reactive aggregate metrics.
Common Patterns
Code using this pattern commonly includes, when relevant:
registerWorker(url, {workerName})— worker initialization- trigger
state::set,state::get— CRUD via state module registerTrigger({type: 'state', function_id, config: {scope}})— reactive side effects on state change- Event argument destructuring in reactive handlers:
async (event) => {const {new_value, old_value, key} = event} trigger({function_id: 'stream::send', payload, action: TriggerAction.Void()})— push live updates to clientsconst logger = new Logger()— structured logging inside handlers
Adapting This Pattern
Use the adaptations below when they apply to the task.
- State triggers fire on any change in the scope — use the
eventargument (new_value,old_value,key) to determine what changed - Multiple functions can react to the same scope independently (on-change and update-metrics both watch
todos) - Stream clients connect via
ws://host:port/stream/{stream_name}/{group_id} - Keep reactive functions fast — offload heavy work to queues if needed
Pattern Boundaries
- If the request focuses on registering external/legacy HTTP endpoints via
registerFunction(especially with endpoint lists like{path, id}plus iteration), preferiii-http-invoked-functions. - Stay with
iii-reactive-backendwhen state scopes, state triggers, and live stream updates are the core requirement.
When to Use
- Use this skill when the task is primarily about
iii-reactive-backendin the iii engine. - Triggers when the request directly asks for this pattern or an equivalent implementation.
Boundaries
- Never use this skill as a generic fallback for unrelated tasks.
- You must not apply this skill when a more specific iii skill is a better fit.
- Always verify environment and safety constraints before applying examples from this skill.