Core API
•3 min read
Core API Overview
The Core API is the foundation of every Directive application. Six primitives work together to express complex behavior declaratively.
The Six Primitives
| Primitive | Role | Analogy |
|---|---|---|
| Facts | Observable state | Database rows |
| Derivations | Computed values from facts | SQL views |
| Constraints | Rules that must be true | Business rules |
| Resolvers | How to fulfill requirements | API calls, side effects |
| Effects | Fire-and-forget reactions | Logging, analytics |
| Events | External inputs | Button clicks, messages |
They compose inside a module, which is created and run as a system. See Module & System for how it all fits together.
How They Relate
Events → mutate Facts → trigger Derivations
→ evaluate Constraints → emit Requirements → Resolvers fulfill them
→ fire Effects (side-effects)
- Facts hold state. When facts change, everything downstream re-evaluates.
- Derivations are auto-tracked computed values – they re-run only when their dependencies change.
- Constraints declare what must be true. When a constraint's
whencondition is met, it emits a requirement. - Resolvers match requirements by type and execute async work to fulfill them.
- Effects run whenever their dependencies change – for logging, analytics, or other side effects.
- Events are typed dispatchers that mutate facts from the outside (UI, network, etc.).
Quick Example
import { createModule, createSystem, t } from '@directive-run/core';
// Define a counter module with typed schema, computed values, and events
const counter = createModule('counter', {
// Declare the shape of all state and computed values up front
schema: {
facts: { count: t.number().default(0) },
derivations: { doubled: t.number() },
events: { increment: {}, decrement: {} },
requirements: {},
},
// Set the initial state when the system starts
init: (facts) => { facts.count = 0; },
// Derivations auto-track their dependencies – no manual subscriptions
derive: {
doubled: (facts) => facts.count * 2,
},
// Events are typed dispatchers that mutate facts from the outside
events: {
increment: (facts) => { facts.count += 1; },
decrement: (facts) => { facts.count -= 1; },
},
});
// Wrap the module in a system to start the reconciliation loop
const system = createSystem({ module: counter });
system.start();
// Dispatch an event to increment, then read the derived value
system.events.increment();
console.log(system.read('doubled')); // 2
Where to Start
- New to Directive? Start with Facts to understand state, then Derivations for computed values.
- Building features? Jump to Constraints and Resolvers for the declarative resolution loop.
- Adding side effects? See Effects for fire-and-forget reactions.
- Handling user input? See Events for typed dispatchers.
- Putting it all together? See Module & System.

