@directive-run/knowledge 1.15.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ai/ai-adapters.md CHANGED
@@ -250,3 +250,8 @@ const orchestrator = createAgentOrchestrator({ runner });
250
250
  | Gemini | `@directive-run/ai/gemini` | `apiKey`, `defaultModel` |
251
251
 
252
252
  All adapters support: `baseURL`, `defaultHeaders`, `hooks`, streaming variant.
253
+
254
+ ## See also
255
+
256
+ - [`ai-orchestrator.md`](./ai-orchestrator.md) — where the `AgentRunner` an adapter produces gets consumed
257
+ - [`ai-agents-streaming.md`](./ai-agents-streaming.md) — the `StreamingCallbackRunner` shape each adapter's streaming variant satisfies
@@ -300,3 +300,8 @@ case "guardrail_triggered":
300
300
  | `orchestrator.runStream(agent, input, opts?)` | instance method | Returns `{ stream, result, abort }` |
301
301
  | `createStreamingRunner(baseRunner, opts?)` | `@directive-run/ai` | Wrap a `StreamingCallbackRunner` into a `StreamRunner` |
302
302
  | `createSSETransport(config?)` | `@directive-run/ai` | `{ toResponse, toStream }` for piping a stream to SSE |
303
+
304
+ ## See also
305
+
306
+ - [`ai-adapters.md`](./ai-adapters.md) — provider runners that produce the streams this file consumes
307
+ - [`ai-orchestrator.md`](./ai-orchestrator.md) — `orchestrator.runStream(agent, input)` returns the `{ stream, result, abort }` triple this file documents
@@ -400,3 +400,9 @@ const orchestrator = createAgentOrchestrator({ runner: baseRunner, guardrails: {
400
400
  | `createHealthMonitor(config?)` | returns `HealthMonitor`; push outcomes in via `recordSuccess/Failure` | — |
401
401
  | `createSemanticCache(config)` | returns `SemanticCache`; use via `createSemanticCacheGuardrail({ cache })` | — |
402
402
  | `createConstraintRouter(config)` | returns an `AgentRunner` that picks providers at call time | — |
403
+
404
+ ## See also
405
+
406
+ - [`ai-orchestrator.md`](./ai-orchestrator.md) — `circuitBreaker` / `selfHealing` / `agentRetry` / `maxTokenBudget` options on `createAgentOrchestrator`
407
+ - [`ai-guardrails-memory.md`](./ai-guardrails-memory.md) — `createSemanticCacheGuardrail({ cache })` wires this file's `SemanticCache` into the orchestrator
408
+ - [`ai-debug-observability.md`](./ai-debug-observability.md) — recording retry storms, circuit-breaker state changes, and budget warnings in the debug timeline
@@ -297,3 +297,8 @@ return JSON.stringify({ ...JSON.parse(input), researchData: data, timestamp: Dat
297
297
  | `network.delegate(from, to, task, context)` | Delegated task with result | `Promise<DelegationResultMessage>` |
298
298
  | `orchestrator.system.facts[agentId].x` | Cross-agent fact read | each agent is a namespaced module |
299
299
  | `context.scratchpad` | Per-pattern ephemeral state | Readonly inside tasks/agents |
300
+
301
+ ## See also
302
+
303
+ - [`ai-multi-agent.md`](./ai-multi-agent.md) — the orchestrator that owns the namespaced facts this file's primitives read
304
+ - [`ai-tasks.md`](./ai-tasks.md) — tasks share the scratchpad surface this file documents
@@ -321,3 +321,9 @@ timeline.subscribe((e) => {
321
321
  | `createOtelPlugin(config)` | Plugin that emits spans for orchestrator activity |
322
322
  | `createOTLPExporter(config)` | Returns `{ exportMetrics, exportTraces }` for OTel backends |
323
323
  | `createDevtoolsServer({ timeline, port })` | WebSocket-bridged timeline for browser devtools |
324
+
325
+ ## See also
326
+
327
+ - [`ai-orchestrator.md`](./ai-orchestrator.md) — `debug: { verboseTimeline }` config + `orchestrator.timeline` access + breakpoint surface
328
+ - [`ai-budget-resilience.md`](./ai-budget-resilience.md) — retry storms, circuit-breaker state changes, and budget warnings all flow through the debug timeline
329
+ - [`ai-testing-evals.md`](./ai-testing-evals.md) — `createTestTimeline` and `assertTimelineEvents` for asserting against recorded events
@@ -362,3 +362,9 @@ await memory.manage(); // awaits the async summarizer
362
362
  | `createOutputTypeGuardrail` | output | `type` |
363
363
  | `createLengthGuardrail` | output | one of `maxCharacters` or `maxTokens` |
364
364
  | `createContentFilterGuardrail` | output | `blockedPatterns` |
365
+
366
+ ## See also
367
+
368
+ - [`ai-orchestrator.md`](./ai-orchestrator.md) — `guardrails: { input, output, toolCall }` and `memory:` options on `createAgentOrchestrator`
369
+ - [`ai-security.md`](./ai-security.md) — `createPIIGuardrail`, `createPromptInjectionGuardrail`, `createAuditTrail`, `createCompliance` — the security-flavored guardrails
370
+ - [`ai-budget-resilience.md`](./ai-budget-resilience.md) — `createSemanticCache` pairs with `createSemanticCacheGuardrail` for caching-as-guardrail
package/ai/ai-mcp-rag.md CHANGED
@@ -286,3 +286,8 @@ type EmbedderFn = (text: string) => Promise<number[]>;
286
286
  | `createBatchedEmbedder(config)` | `@directive-run/ai` | `{ embed, flush, dispose }` | Wrap an EmbedderFn with batching |
287
287
  | `createTestEmbedder(dim?)` | `@directive-run/ai` | `EmbedderFn` | Deterministic embedder for tests |
288
288
  | `createJSONFileStore(options)` | `@directive-run/ai` | `RAGStorage` | File-backed vector store for prototyping |
289
+
290
+ ## See also
291
+
292
+ - [`ai-orchestrator.md`](./ai-orchestrator.md) — where MCP-supplied tools and RAG-enriched runners flow into agent runs
293
+ - [`ai-security.md`](./ai-security.md) — `toolConstraints[…].requireApproval` and the per-tool approval workflow the MCP adapter exposes
@@ -366,3 +366,10 @@ orch.start();
366
366
  | `race(handlers, options?)` | `string[], { timeout?, minSuccess?, extract? }` | — |
367
367
  | `debate(config)` | `{ handlers, evaluator, maxRounds?, extract?, parseJudgement? }` | — (single arg) |
368
368
  | `goal(nodes, when, options?)` | `Record<string, GoalNode>, (facts) => boolean, { maxSteps?, extract?, satisfaction? }` | when |
369
+
370
+ ## See also
371
+
372
+ - [`ai-orchestrator.md`](./ai-orchestrator.md) — the single-agent flavor; covers options and lifecycle this file builds on
373
+ - [`ai-communication.md`](./ai-communication.md) — `createMessageBus` / `createAgentNetwork` for inter-agent messaging within a pattern
374
+ - [`ai-tasks.md`](./ai-tasks.md) — deterministic task handlers that compose with agents inside `dag` / `sequential` patterns
375
+ - [`ai-testing-evals.md`](./ai-testing-evals.md) — `createTestMultiAgentOrchestrator` and pattern-shape assertions
@@ -455,3 +455,12 @@ const final = await result;
455
455
  | `orch.facts.agent.*` | Read built-in agent state |
456
456
  | `orch.totalTokens` | Cumulative token count |
457
457
  | `orch.timeline` | DebugTimeline (when `debug: true`); `null` otherwise |
458
+
459
+ ## See also
460
+
461
+ - [`ai-multi-agent.md`](./ai-multi-agent.md) — the multi-agent flavor; 8 composition patterns and pattern factories
462
+ - [`ai-adapters.md`](./ai-adapters.md) — provider runners that produce the `runner` this orchestrator wraps
463
+ - [`ai-guardrails-memory.md`](./ai-guardrails-memory.md) — full surface of the `guardrails:` and `memory:` options on this orchestrator
464
+ - [`ai-budget-resilience.md`](./ai-budget-resilience.md) — full surface of the `circuitBreaker:`, `selfHealing:`, `agentRetry:`, `maxTokenBudget:` options
465
+ - [`ai-debug-observability.md`](./ai-debug-observability.md) — full surface of the `debug:`, `breakpoints:`, `onBreakpoint:` options + `orchestrator.timeline`
466
+ - [`ai-testing-evals.md`](./ai-testing-evals.md) — `createTestOrchestrator` for unit testing this surface
package/ai/ai-security.md CHANGED
@@ -393,3 +393,8 @@ createCompliance({
393
393
  | `createToolGuardrail` | `@directive-run/ai/guardrails` | guardrail | Tool allow/deny lists |
394
394
  | `createContentFilterGuardrail` | `@directive-run/ai/guardrails` | guardrail | Block sensitive patterns (block-only — no redact) |
395
395
  | `GuardrailError` / `isGuardrailError` | `@directive-run/ai` | error class + guard | Carries `code`, `guardrailName`, `userMessage` |
396
+
397
+ ## See also
398
+
399
+ - [`ai-guardrails-memory.md`](./ai-guardrails-memory.md) — the broader guardrail surface (length, schema, content filter, tool allowlist) this file's security-flavored guardrails compose with
400
+ - [`ai-mcp-rag.md`](./ai-mcp-rag.md) — `toolConstraints[…].requireApproval` is where MCP tool calls thread into the approval workflow surfaced here
package/ai/ai-tasks.md CHANGED
@@ -261,3 +261,8 @@ tasks: {
261
261
  | Concurrency control | Via patterns | `maxConcurrent` |
262
262
  | Scratchpad access | No | Yes |
263
263
  | Works in all patterns | Yes | Yes |
264
+
265
+ ## See also
266
+
267
+ - [`ai-multi-agent.md`](./ai-multi-agent.md) — tasks share the `handler:` namespace with agents inside `dag` / `sequential` / `parallel` patterns
268
+ - [`ai-communication.md`](./ai-communication.md) — tasks read the scratchpad this file's `context.scratchpad` surface exposes
@@ -477,3 +477,9 @@ const suite = createEvalSuite({
477
477
  | `assertOrchestratorState` / `assertMultiAgentState` / `assertScratchpadState` / `assertDerivedValues` / `assertTimelineEvents` / `assertDagExecution` / `assertBreakpointHit` / `assertRerouted` / `assertAgentHealth` / `assertCheckpoint` / `assertMultiplexedStream` | `@directive-run/ai/testing` | State/topology/event assertions |
478
478
  | `createEvalSuite` | `@directive-run/ai/evals` | Dataset-driven multi-criterion eval runner |
479
479
  | `evalCost` / `evalLatency` / `evalOutputLength` / `evalSafety` / `evalStructure` / `evalMatch` / `evalJudge` / `evalFaithfulness` / `evalRelevance` / `evalCoherence` / `evalAssert` | `@directive-run/ai/evals` | Built-in criterion factories |
480
+
481
+ ## See also
482
+
483
+ - [`ai-orchestrator.md`](./ai-orchestrator.md) — `createTestOrchestrator` wraps this orchestrator; the prod surface is what your tests are exercising
484
+ - [`ai-multi-agent.md`](./ai-multi-agent.md) — `createTestMultiAgentOrchestrator` for testing pattern execution
485
+ - [`ai-debug-observability.md`](./ai-debug-observability.md) — recorded debug events feed `assertTimelineEvents` / `assertDagExecution` / `assertBreakpointHit`
@@ -371,3 +371,12 @@ Before generating any Directive code, verify:
371
371
  8. Multi-module uses `facts.self.*` for own facts
372
372
  9. Imports from `@directive-run/core`, not deep paths
373
373
  10. `await system.settle()` after `system.start()`
374
+
375
+ ## See also
376
+
377
+ - [`naming.md`](./naming.md) — the strict canonical-term rules AND the alias map for cross-paradigm searches
378
+ - [`constraints.md`](./constraints.md) — the constraint shape these anti-patterns reference (`facts` not in scope inside static `require:`, etc.)
379
+ - [`resolvers.md`](./resolvers.md) — the resolver shape these anti-patterns reference (return `void`, mutate `context.facts`, `(req, context)` not `(req, ctx)`)
380
+ - [`schema-types.md`](./schema-types.md) — the `t.*()` builders that exist and the hallucinated ones (`t.map`, `t.set`, `t.promise`, `t.date`) that don't
381
+ - [`react-adapter.md`](./react-adapter.md) — the React hooks that exist and the hallucinated ones (`useEvent`, `useSystem`, `DirectiveProvider`) that don't
382
+ - [`error-boundaries.md`](./error-boundaries.md) — error-handling shapes AI assistants sometimes invent
@@ -265,3 +265,10 @@ constraints: {
265
265
  "Whenever X changes, log it" → Effect
266
266
  "X is always facts.a + facts.b" → Derivation
267
267
  ```
268
+
269
+ ## See also
270
+
271
+ - [`resolvers.md`](./resolvers.md) — the other half of the constraint-resolver loop; the supply side that fulfills the requirements constraints emit
272
+ - [`core-patterns.md`](./core-patterns.md) — how constraints fit into the module shape alongside facts, derivations, events, and effects
273
+ - [`multi-module.md`](./multi-module.md) — `crossModuleDeps` for constraints that fire on facts owned by another module
274
+ - [`anti-patterns.md`](./anti-patterns.md) — the constraint-shaped mistakes AI assistants reliably make
@@ -228,3 +228,13 @@ const typed = createModule("typed", {
228
228
  },
229
229
  });
230
230
  ```
231
+
232
+ ## See also
233
+
234
+ - [`constraints.md`](./constraints.md) — the demand side of the constraint-resolver loop
235
+ - [`resolvers.md`](./resolvers.md) — the supply side that fulfills requirements
236
+ - [`schema-types.md`](./schema-types.md) — the `t.*()` builders that define fact and derivation types
237
+ - [`multi-module.md`](./multi-module.md) — when a single module isn't enough
238
+ - [`system-api.md`](./system-api.md) — `createSystem` and the runtime instance once your module is defined
239
+ - [`naming.md`](./naming.md) — terminology conventions every example here follows
240
+ - [`testing.md`](./testing.md) — `createTestSystem` for the modules you're learning to write
@@ -322,3 +322,9 @@ try {
322
322
  6. Add `onError` callback for logging/monitoring
323
323
  7. Use `"throw"` for derivation errors (they indicate bugs)
324
324
  8. Use `"skip"` for non-critical effects (logging, analytics)
325
+
326
+ ## See also
327
+
328
+ - [`resolvers.md`](./resolvers.md) — retry policies and cancellation; the most common error source
329
+ - [`plugins.md`](./plugins.md) — `createCircuitBreaker` lives in `@directive-run/core/plugins`; pair it with error boundaries for cascading-failure isolation
330
+ - [`anti-patterns.md`](./anti-patterns.md) — common error-handling mistakes (catching the wrong type, swallowing recoverable errors)
package/core/history.md CHANGED
@@ -344,3 +344,8 @@ const system = createSystem({
344
344
  history: true,
345
345
  });
346
346
  ```
347
+
348
+ ## See also
349
+
350
+ - [`system-api.md`](./system-api.md) — `history` config in `createSystem` + the full `system.history.*` API
351
+ - [`testing.md`](./testing.md) — replay-driven testing patterns that pair with recorded snapshots
@@ -318,3 +318,10 @@ system.events.cart.addItem({ id: "item-1", qty: 1 });
318
318
  // object form is valid.
319
319
  system.dispatch({ type: "login", token: "abc" });
320
320
  ```
321
+
322
+ ## See also
323
+
324
+ - [`core-patterns.md`](./core-patterns.md) — start here for the single-module shape before going namespaced
325
+ - [`system-api.md`](./system-api.md) — `createSystem({ modules: { ... } })` and the namespaced facts proxy
326
+ - [`constraints.md`](./constraints.md) — `crossModuleDeps` for constraints that fire on facts owned by another module
327
+ - [`naming.md`](./naming.md) — `facts.self.*` convention; dot-notation vs bracket-notation rules
package/core/naming.md CHANGED
@@ -2,81 +2,116 @@
2
2
 
3
3
  > Covers all `@directive-run/*` packages — terminology, parameter names, return-style rules.
4
4
 
5
- Directive naming rules that AI coding assistants must follow. These are non-negotiable project conventions.
5
+ Directive uses precise vocabulary by design: each concept has one canonical name across every package, every language adapter, and every doc. The names are non-negotiable for code Directive ships, AND every term has a cross-paradigm alias so a developer coming from Redux / Zustand / XState / Jotai / React Query can find the right Directive concept on the first search.
6
6
 
7
- ## Decision Tree: "What do I call this?"
7
+ This file is both the rules and the bridge. Search for the term you already know; you'll land on the Directive equivalent.
8
8
 
9
- ```
10
- Resolver parameter names?
11
- → (req, context) req = requirement, NEVER "request"
12
- → NEVER (req, ctx) context is NEVER abbreviated
9
+ ## Coming from another library? Start here
13
10
 
14
- Computed values?
15
- → "derivations" / derive NEVER "computed", "selectors", "getters"
16
- system.derive.myValue NEVER system.computed.myValue
11
+ | If you call it… | (in this library) | Directive calls it… | Why the name |
12
+ |---|---|---|---|
13
+ | **state**, **store**, **atom**, **signal**, **observable** | Redux, Zustand, Jotai, Preact Signals, MobX | **facts** | "Facts about the world" — the system observes them. Same value-bag role as state, with a proxy that auto-tracks reads. |
14
+ | **selector**, **computed**, **getter**, **memo**, **derived store** | Redux, Vue/MobX, Zustand getters, Memoize, Svelte | **derivations** / `derive` | Auto-tracked computed values. No dep arrays. Directive's name aligns with "derived from facts." |
15
+ | **action**, **dispatch**, **reducer**, **command**, **intent** | Redux, Redux Toolkit, CQRS | **events** + **resolvers** | Events are the user-facing trigger; resolvers fulfill them. Reducers are split into the two halves Directive cares about. |
16
+ | **thunk**, **saga**, **effect**, **middleware**, **listener** | Redux Toolkit, redux-saga, redux-observable, NgRx | **resolvers** | Async logic that mutates state in response to a requirement. Same role as a thunk; declared once, run by the runtime. |
17
+ | **rule**, **condition**, **guard**, **trigger**, **policy** | XState guards, Cerbos, OPA, business-rule engines | **constraints** | Declarative "when X is true, Y must happen." Constraints emit requirements; resolvers fulfill them. |
18
+ | **request**, **query**, **side-effect spec** | React Query / TanStack Query queries, Apollo queries | **requirements** | The object a constraint emits. The runtime dedupes them, dispatches to resolvers, tracks status. |
19
+ | **subscription**, **listener**, **reaction**, **watcher** | Zustand subscribe, MobX reactions, Redux subscriptions | **effects** | Side-effects that run when watched facts change. Cleaner than `subscribe()` callbacks because effects auto-track. |
20
+ | **slice**, **feature**, **domain**, **bounded context** | Redux Toolkit slices, NgRx feature modules | **modules** | Encapsulates facts + derivations + constraints + resolvers + events for one bounded slice of the system. |
21
+ | **store**, **container**, **context**, **app state** | Redux Store, Pinia, React Context, NgRx Store | **system** | The runtime that wires modules together, evaluates constraints, dispatches resolvers, and exposes observation. |
22
+ | **state machine**, **statechart**, **xstate machine** | XState | (closest: **module** + **constraints**) | Directive isn't a state machine — but if your XState `states` model business rules (not UI flow), constraints + facts express the same logic declaratively with no transition functions. |
23
+ | **cache**, **query cache**, **stale-while-revalidate** | TanStack Query, SWR, Apollo cache | (closest: `@directive-run/query` + **constraints**) | Use `@directive-run/query` for the cache; constraints decide when refetches fire. Directive doesn't replace TanStack Query — it composes with it. |
24
+ | **agent**, **chain**, **graph**, **workflow** | LangChain, LangGraph, OpenAI Assistants | **agent** + **orchestrator** | `@directive-run/ai` keeps the names — agents are agents, orchestrators are orchestrators — but they run under the same constraint engine as the rest of Directive. |
25
+ | **guardrail**, **filter**, **safety check**, **moderation** | OpenAI moderation API, NVIDIA NeMo Guardrails | **guardrails** | Same name, same role; declarative input/output/tool-call checks. |
17
26
 
18
- State values?
19
- → "facts" NEVER "state", "store", "atoms"
20
- → system.facts.count NEVER system.state.count
27
+ If your term isn't in the table, search the canonical name in this doc's [Terminology quick reference](#terminology-quick-reference) — both directions are listed.
21
28
 
22
- Conditional triggers?
23
- → "constraints" NEVER "rules", "conditions", "triggers"
24
- → when() + require() NEVER if/then, trigger/action
29
+ ## Canonical terms (non-negotiable for code Directive ships)
25
30
 
26
- Fulfillment logic?
27
- → "resolvers" NEVER "handlers", "actions", "reducers"
28
- resolve(req, context) NEVER handle(req, ctx)
29
- ```
31
+ Above is the bridge from your existing vocabulary. Below are the canonical names — the only ones that should appear in `@directive-run/*` source, tests, docs, and generated AI rules.
32
+
33
+ ### `facts` the value bag
34
+
35
+ Not state, not store, not atoms. **Facts.** Accessed at `system.facts.x`. Mutated through events and resolvers. Read through derivations, hooks, and `system.facts.$store`.
36
+
37
+ ### `derivations` — auto-tracked computed values
38
+
39
+ Declared via `derive: { name: (facts) => … }`. Read at `system.derive.name`. The hook is `useDerived` (not `useComputed`, not `useSelector` — Directive's `useSelector` is a different, broader primitive that takes a selector function).
40
+
41
+ ### `constraints` — when-then declarations
42
+
43
+ Declared via `constraints: { name: { when: …, require: … } }`. The `when` returns a boolean; the `require` returns a requirement.
44
+
45
+ ### `resolvers` — requirement fulfillment
46
+
47
+ Declared via `resolvers: { name: { requirement: …, resolve: async (req, context) => … } }`. Mutate `context.facts`; never return data from `resolve`.
48
+
49
+ ### `requirements` — what constraints emit
50
+
51
+ Tagged union `{ type: "FETCH_USER", … }`. Constraints emit them; the runtime dedupes by `type` + `key()`; resolvers fulfill them.
52
+
53
+ ### `effects` — side effects from watched changes
54
+
55
+ Declared via `effects: { name: { run: (facts, prev) => … } }`. Run on relevant fact changes. The auto-tracking dependency model means no `deps` array unless you specifically need a partial dep set.
56
+
57
+ ### `events` — typed mutation entry points
58
+
59
+ Declared via `events: { name: (facts, payload) => … }`. Called as `system.events.name(payload)`. The typed events accessor is the canonical way to dispatch — `system.dispatch({type, ...payload})` works but the typed accessor carries autocomplete.
30
60
 
31
- ## Parameter Naming
61
+ ### `module` — bounded slice
62
+
63
+ Created via `createModule(name, { schema, init, derive, effects, events, constraints, resolvers })`. Composes into systems.
64
+
65
+ ### `system` — the runtime
66
+
67
+ Created via `createSystem({ module })` or `createSystem({ modules: { x, y } })`. Hosts the reconciliation loop.
68
+
69
+ ## Parameter naming
32
70
 
33
71
  ### `req` = requirement (NOT request)
34
72
 
35
- The `req` parameter in resolvers and constraint `key()` functions is short for **requirement** -- the object emitted by a constraint's `require` property.
73
+ The `req` parameter in resolvers and constraint `key()` functions is short for **requirement** the object emitted by a constraint's `require` property.
36
74
 
37
75
  ```typescript
38
- // CORRECT req is a requirement
76
+ // CORRECT req is a requirement
39
77
  resolvers: {
40
78
  fetchUser: {
41
79
  requirement: "FETCH_USER",
42
80
  key: (req) => `fetch-${req.userId}`,
43
81
  resolve: async (req, context) => {
44
82
  // req.type === "FETCH_USER"
45
- // req.userId from the requirement payload
46
83
  const user = await fetchUser(req.userId);
47
84
  context.facts.user = user;
48
85
  },
49
86
  },
50
87
  },
51
88
 
52
- // WRONG never use "request" or "r"
89
+ // WRONG never "request" or "r"
53
90
  resolve: async (request, context) => { /* ... */ },
54
91
  resolve: async (r, context) => { /* ... */ },
55
92
  ```
56
93
 
57
- ### `context` is Never Abbreviated
94
+ ### `context` is never abbreviated
58
95
 
59
96
  ```typescript
60
97
  // CORRECT
61
98
  resolve: async (req, context) => {
62
99
  context.facts.status = "loaded";
63
- context.signal; // AbortSignal
64
- context.snapshot(); // facts snapshot
100
+ context.signal; // AbortSignal
101
+ context.snapshot(); // facts snapshot
65
102
  },
66
103
 
67
- // WRONG never abbreviate to ctx
104
+ // WRONG never abbreviate to ctx
68
105
  resolve: async (req, ctx) => { /* ... */ },
69
106
  ```
70
107
 
71
- ## Return Style
108
+ ## Return style
72
109
 
73
- ### Always Use Braces (for `if` blocks with `return`)
110
+ ### Braces for `if` blocks with `return` (NOT for arrow expressions)
74
111
 
75
112
  The brace rule applies to control-flow blocks — not to arrow-expression bodies.
76
113
 
77
- **Arrow expressions** (single-line derivations, predicates, computed
78
- requirements): the concise form is preferred. No braces, no explicit
79
- `return`.
114
+ **Arrow expressions** (single-line derivations, predicates, computed requirements): the concise form is preferred. No braces, no explicit `return`.
80
115
 
81
116
  ```typescript
82
117
  // CORRECT — single-line arrow expressions stay concise
@@ -93,25 +128,24 @@ constraints: {
93
128
  },
94
129
  ```
95
130
 
96
- **Control-flow statements** (`if`, `for`, `while`): braces required, even
97
- for single-line bodies. Single-line `if (x) return y` shapes are never used.
131
+ **Control-flow statements** (`if`, `for`, `while`): braces required, even for single-line bodies. Single-line `if (x) return y` shapes are never used.
98
132
 
99
133
  ```typescript
100
- // WRONG single-line if return
134
+ // WRONG single-line if return
101
135
  if (facts.user) return "ready";
102
136
 
103
- // CORRECT always wrap the body in braces
137
+ // CORRECT always wrap the body in braces
104
138
  if (facts.user) {
105
139
  return "ready";
106
140
  }
107
141
  ```
108
142
 
109
- ### Blank Line Before `return`
143
+ ### Blank line before `return`
110
144
 
111
145
  Add a blank line before `return` when there is code above it. Skip the blank line when `return` is the first statement in a block.
112
146
 
113
147
  ```typescript
114
- // CORRECT blank line before return when code precedes it
148
+ // CORRECT blank line before return when code precedes it
115
149
  function getStatus(facts) {
116
150
  const phase = facts.phase;
117
151
  const hasUser = facts.user !== null;
@@ -119,12 +153,12 @@ function getStatus(facts) {
119
153
  return phase === "ready" && hasUser;
120
154
  }
121
155
 
122
- // CORRECT no blank line when return is first statement
156
+ // CORRECT no blank line when return is first statement
123
157
  function isReady(facts) {
124
158
  return facts.phase === "ready";
125
159
  }
126
160
 
127
- // CORRECT blank line after brace-style return block
161
+ // CORRECT blank line after brace-style return block
128
162
  function process(facts) {
129
163
  if (!facts.ready) {
130
164
  return null;
@@ -134,26 +168,20 @@ function process(facts) {
134
168
 
135
169
  return result;
136
170
  }
137
-
138
- // WRONG – no blank line before return after code
139
- function getStatus(facts) {
140
- const phase = facts.phase;
141
- return phase === "ready"; // Missing blank line
142
- }
143
171
  ```
144
172
 
145
- ## Multi-Line Code Formatting
173
+ ## Multi-line code formatting
146
174
 
147
175
  Never put properties or statements on a single line inside braces. Always expand to one item per line with proper indentation. This applies everywhere: schema definitions, init functions, events, effects, requirement types, and any other object or block.
148
176
 
149
177
  ```typescript
150
- // WRONG properties crammed on one line
178
+ // WRONG properties crammed on one line
151
179
  schema: {
152
180
  facts: { phase: t.string(), count: t.number() },
153
181
  requirements: { FETCH_USER: { id: t.string() }, RESET: {} },
154
182
  },
155
183
 
156
- // CORRECT one property per line, always expanded
184
+ // CORRECT one property per line, always expanded
157
185
  schema: {
158
186
  facts: {
159
187
  phase: t.string(),
@@ -167,41 +195,31 @@ schema: {
167
195
  },
168
196
  },
169
197
 
170
- // WRONG statements crammed on one line
198
+ // WRONG statements crammed on one line
171
199
  init: (facts) => { facts.phase = "idle"; facts.count = 0; },
172
200
 
173
- // CORRECT one statement per line
201
+ // CORRECT one statement per line
174
202
  init: (facts) => {
175
203
  facts.phase = "idle";
176
204
  facts.count = 0;
177
205
  },
178
-
179
- // WRONG
180
- events: { reset: (facts) => { facts.count = 0; facts.phase = "idle"; } },
181
-
182
- // CORRECT
183
- events: {
184
- reset: (facts) => {
185
- facts.count = 0;
186
- facts.phase = "idle";
187
- },
188
- },
189
206
  ```
190
207
 
191
208
  Single-expression arrows (no braces) are fine on one line. Empty objects `{}` are fine inline.
209
+
192
210
  ```typescript
193
- // OK single expression, no braces
211
+ // OK single expression, no braces
194
212
  derive: {
195
213
  isReady: (facts) => facts.phase === "ready",
196
214
  },
197
215
 
198
- // OK empty object
216
+ // OK empty object
199
217
  RESET: {},
200
218
  ```
201
219
 
202
- ## Multi-Module Naming
220
+ ## Multi-module naming
203
221
 
204
- ### `facts.self.*` for Own Module
222
+ ### `facts.self.*` for own module
205
223
 
206
224
  In multi-module systems, constraints, effects, and derivations with `crossModuleDeps` receive namespaced facts. Own module facts are always at `facts.self.*`.
207
225
 
@@ -214,7 +232,7 @@ constraints: {
214
232
  },
215
233
  },
216
234
 
217
- // WRONG bare facts.* in multi-module context
235
+ // WRONG bare facts.* in multi-module context
218
236
  constraints: {
219
237
  loadWhenAuth: {
220
238
  when: (facts) => facts.isAuthenticated && !facts.loaded,
@@ -223,48 +241,48 @@ constraints: {
223
241
  },
224
242
  ```
225
243
 
226
- ### System-Level Access Uses Dot Notation
244
+ ### System-level access uses dot notation
227
245
 
228
246
  ```typescript
229
- // CORRECT dot notation through namespace proxy
247
+ // CORRECT dot notation through namespace proxy
230
248
  system.facts.auth.token;
231
249
  system.facts.cart.items;
232
250
  system.derive.auth.isLoggedIn;
233
251
  system.events.auth.login({ token: "..." });
234
252
 
235
- // WRONG bracket notation with internal separator
253
+ // WRONG bracket notation with internal separator
236
254
  system.facts["auth::token"];
237
255
  system.facts["auth_token"];
238
256
  ```
239
257
 
240
- ## Type Casting Rules
258
+ ## Type casting rules
241
259
 
242
- ### Never Cast When Reading
260
+ ### Never cast when reading
243
261
 
244
262
  The schema provides all types. Do not add `as` casts when reading facts or derivations from the system.
245
263
 
246
264
  ```typescript
247
- // CORRECT schema provides the type
265
+ // CORRECT schema provides the type
248
266
  const profile = system.facts.profile;
249
267
  const isReady = system.derive.isReady;
250
268
 
251
- // WRONG unnecessary cast
269
+ // WRONG unnecessary cast
252
270
  const profile = system.facts.profile as UserProfile;
253
271
  const isReady = system.derive.isReady as boolean;
254
272
  ```
255
273
 
256
- ### Cast Only in Schema Definition
274
+ ### Cast only in schema definition
257
275
 
258
- Type assertions are only valid in schema definition using the `{} as {}` pattern:
276
+ Type assertions are only valid in schema definition using the `{} as {}` pattern, or via the `t.*` builders (preferred):
259
277
 
260
278
  ```typescript
261
- // CORRECT cast in schema definition
279
+ // CORRECT cast in schema definition
262
280
  schema: {
263
281
  facts: {} as { profile: UserProfile; settings: AppSettings },
264
282
  derivations: {} as { displayName: string },
265
283
  },
266
284
 
267
- // OR use t.* builders (preferred)
285
+ // PREFERRED t.* builders
268
286
  schema: {
269
287
  facts: {
270
288
  profile: t.object<UserProfile>(),
@@ -276,17 +294,28 @@ schema: {
276
294
  },
277
295
  ```
278
296
 
279
- ## Terminology Quick Reference
297
+ ## Terminology quick reference
298
+
299
+ Two-way lookup. Search the term you know.
280
300
 
281
- | Directive Term | NEVER Use |
301
+ | Directive term | Cross-paradigm aliases (use these to search) |
282
302
  |---|---|
283
- | facts | state, store, atoms, signals |
284
- | derivations / derive | computed, selectors, getters, memos |
285
- | constraints | rules, conditions, triggers, guards |
286
- | resolvers | handlers, actions, reducers, sagas |
287
- | requirements | requests, commands, intents |
288
- | effects | watchers, subscriptions, reactions |
289
- | module | slice, feature, domain |
290
- | system | store, container, context |
291
- | `req` (parameter) | request, r, requirement (spelled out) |
292
- | `context` (parameter) | ctx, c, resolverContext |
303
+ | **facts** | state, store, atoms, signals, observables, model |
304
+ | **derivations** / `derive` | computed, selectors, getters, memos, derived stores, $: blocks (Svelte) |
305
+ | **constraints** | rules, conditions, triggers, guards, policies, invariants |
306
+ | **resolvers** | handlers, actions, reducers, sagas, thunks, effects (Redux), middleware, listeners |
307
+ | **requirements** | requests, commands, intents, queries (TanStack), tasks |
308
+ | **effects** | watchers, subscriptions, reactions, autoruns, listeners |
309
+ | **events** | actions, intents, commands, methods (Pinia), signals (NgRx) |
310
+ | **module** | slice, feature, domain, bounded context, NgRx feature module |
311
+ | **system** | store, container, context, app state, app shell |
312
+ | **`req`** (parameter) | request, r, requirement (spelled out) |
313
+ | **`context`** (parameter) | ctx, c, resolverContext |
314
+
315
+ The forbidden direction is also non-negotiable: in code Directive ships, the columns reverse. Do NOT use `state`, `store`, `selectors`, `computed`, `actions`, `reducers`, `subscriptions`, `slices`, `request`, or `ctx` in `@directive-run/*` source. The alias map is for retrieval — the canonical names are for code.
316
+
317
+ ## See also
318
+
319
+ - [`core-patterns.md`](./core-patterns.md) — the actual code shapes every naming rule here applies to
320
+ - [`multi-module.md`](./multi-module.md) — `facts.self.*` convention and dot-notation rules
321
+ - [`anti-patterns.md`](./anti-patterns.md) — naming-shaped mistakes (`request` for `req`, `ctx` for `context`, hallucinated TS schema types)
package/core/plugins.md CHANGED
@@ -354,3 +354,8 @@ persistencePlugin({
354
354
  exclude: ["authToken", "isLoading", "error"],
355
355
  })
356
356
  ```
357
+
358
+ ## See also
359
+
360
+ - [`system-api.md`](./system-api.md) — `plugins:` option on `createSystem` and the lifecycle hooks plugins observe
361
+ - [`error-boundaries.md`](./error-boundaries.md) — `createCircuitBreaker` and the resilience plugins that pair with error boundaries
@@ -368,3 +368,9 @@ const handleClick = useCallback(() => events.increment(), [events]);
368
368
  const events = useEvents(system);
369
369
  <button onClick={() => events.increment()}>+</button>
370
370
  ```
371
+
372
+ ## See also
373
+
374
+ - [`system-api.md`](./system-api.md) — the system instance the hooks here read from + the SSR/hydration story
375
+ - [`core-patterns.md`](./core-patterns.md) — the module shape every React example here assumes you've built
376
+ - [`anti-patterns.md`](./anti-patterns.md) — the hallucinated React hooks (`useEvent`, `useSystem`, `DirectiveProvider`) that AI assistants reach for
package/core/resolvers.md CHANGED
@@ -357,3 +357,11 @@ system.start();
357
357
  await system.settle();
358
358
  console.log(system.facts.data); // Resolved value
359
359
  ```
360
+
361
+ ## See also
362
+
363
+ - [`constraints.md`](./constraints.md) — the demand side of the loop; what emits the requirements this resolver fulfills
364
+ - [`core-patterns.md`](./core-patterns.md) — how resolvers fit into the module shape
365
+ - [`error-boundaries.md`](./error-boundaries.md) — recovery strategies when a resolver throws (retry, fallback, circuit breaker)
366
+ - [`testing.md`](./testing.md) — mock resolvers via `mocks.resolvers` and the programmatic `mockResolver(type)` helper
367
+ - [`anti-patterns.md`](./anti-patterns.md) — the resolver-shaped mistakes (returning data from `resolve`, abbreviating `context` to `ctx`)
@@ -265,3 +265,9 @@ const myModule = createModule("simple", {
265
265
  ```
266
266
 
267
267
  This gives full TypeScript inference but skips runtime validation. Use `t.*()` when you want dev-mode validation, transforms, or self-documenting schemas.
268
+
269
+ ## See also
270
+
271
+ - [`core-patterns.md`](./core-patterns.md) — where the schemas these builders define get attached (modules)
272
+ - [`system-api.md`](./system-api.md) — schema flows through `createSystem` and shows up on `system.facts.*`
273
+ - [`anti-patterns.md`](./anti-patterns.md) — hallucinated schema types (`t.map`, `t.set`, `t.date`, `t.promise`, `t.tuple`, `t.record`, `t.any`) that don't exist
@@ -453,3 +453,11 @@ system.start();
453
453
  system.stop();
454
454
  system.destroy();
455
455
  ```
456
+
457
+ ## See also
458
+
459
+ - [`core-patterns.md`](./core-patterns.md) — the modules that go into `createSystem({ module: ... })`
460
+ - [`multi-module.md`](./multi-module.md) — `createSystem({ modules: { ... } })` for namespaced systems
461
+ - [`history.md`](./history.md) — the `history:` config and the `system.history.*` time-travel surface
462
+ - [`plugins.md`](./plugins.md) — the `plugins:` config and the lifecycle hooks plugins observe
463
+ - [`react-adapter.md`](./react-adapter.md) — consuming a system from React components
package/core/testing.md CHANGED
@@ -404,3 +404,9 @@ resolve: (req, context) => { context.facts.x = 1; }
404
404
  | `system.assertFactSet(key, value?)` | instance method | Assert a fact value |
405
405
  | `system.assertFactChanges(key, n)` | instance method | Assert the change count for a fact |
406
406
  | `system.waitForIdle(maxWait?)` | instance method | Wait for in-flight resolvers (default 5000ms) |
407
+
408
+ ## See also
409
+
410
+ - [`resolvers.md`](./resolvers.md) — the resolver shape `mocks.resolvers` replaces and the retry/cancel semantics tests need to know about
411
+ - [`core-patterns.md`](./core-patterns.md) — the module shape `createTestSystem({ module })` is testing
412
+ - [`history.md`](./history.md) — recorded snapshots for replay-based testing patterns
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directive-run/knowledge",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "Knowledge files, examples, and validation for Directive — the constraint-driven TypeScript runtime.",
5
5
  "license": "(MIT OR Apache-2.0)",
6
6
  "author": "Jason Comes",
@@ -51,8 +51,8 @@
51
51
  "tsx": "^4.19.2",
52
52
  "typescript": "^5.7.2",
53
53
  "vitest": "^3.0.0",
54
- "@directive-run/core": "1.15.0",
55
- "@directive-run/ai": "1.15.0"
54
+ "@directive-run/core": "1.16.0",
55
+ "@directive-run/ai": "1.16.0"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsx scripts/generate-api-skeleton.ts && tsx scripts/generate-sitemap.ts && tsx scripts/extract-examples.ts && tsup",