@directive-run/claude-plugin 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.
Files changed (83) hide show
  1. package/.claude-plugin/plugin.json +6 -0
  2. package/LICENSE +26 -0
  3. package/README.md +113 -0
  4. package/dist/index.cjs +2 -0
  5. package/dist/index.cjs.map +1 -0
  6. package/dist/index.d.cts +66 -0
  7. package/dist/index.d.ts +66 -0
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -0
  10. package/package.json +64 -0
  11. package/skills/README.md +9 -0
  12. package/skills/building-ai-agents/SKILL.md +414 -0
  13. package/skills/building-ai-agents/ai-adapters.md +257 -0
  14. package/skills/building-ai-agents/ai-agents-streaming.md +307 -0
  15. package/skills/building-ai-agents/ai-communication.md +304 -0
  16. package/skills/building-ai-agents/api-skeleton.md +5 -0
  17. package/skills/building-ai-agents/examples.md +849 -0
  18. package/skills/building-ai-orchestrators/SKILL.md +401 -0
  19. package/skills/building-ai-orchestrators/ai-multi-agent.md +375 -0
  20. package/skills/building-ai-orchestrators/ai-orchestrator.md +466 -0
  21. package/skills/building-ai-orchestrators/ai-tasks.md +268 -0
  22. package/skills/building-ai-orchestrators/api-skeleton.md +5 -0
  23. package/skills/building-ai-orchestrators/examples.md +1609 -0
  24. package/skills/building-directive-systems/SKILL.md +499 -0
  25. package/skills/building-directive-systems/api-skeleton.md +5 -0
  26. package/skills/building-directive-systems/examples.md +4149 -0
  27. package/skills/building-directive-systems/multi-module.md +327 -0
  28. package/skills/building-directive-systems/plugins.md +361 -0
  29. package/skills/building-directive-systems/react-adapter.md +376 -0
  30. package/skills/building-directive-systems/system-api.md +463 -0
  31. package/skills/getting-started-with-directive/SKILL.md +198 -0
  32. package/skills/getting-started-with-directive/api-skeleton.md +5 -0
  33. package/skills/getting-started-with-directive/core-patterns.md +240 -0
  34. package/skills/getting-started-with-directive/examples.md +87 -0
  35. package/skills/getting-started-with-directive/sitemap.md +202 -0
  36. package/skills/hardening-ai-systems/SKILL.md +377 -0
  37. package/skills/hardening-ai-systems/ai-budget-resilience.md +408 -0
  38. package/skills/hardening-ai-systems/ai-guardrails-memory.md +370 -0
  39. package/skills/hardening-ai-systems/ai-security.md +400 -0
  40. package/skills/hardening-ai-systems/api-skeleton.md +5 -0
  41. package/skills/hardening-ai-systems/examples.md +628 -0
  42. package/skills/migrating-to-directive/SKILL.md +249 -0
  43. package/skills/migrating-to-directive/anti-patterns.md +382 -0
  44. package/skills/migrating-to-directive/api-skeleton.md +5 -0
  45. package/skills/migrating-to-directive/core-patterns.md +240 -0
  46. package/skills/migrating-to-directive/examples.md +511 -0
  47. package/skills/migrating-to-directive/schema-types.md +273 -0
  48. package/skills/reviewing-directive-code/SKILL.md +232 -0
  49. package/skills/reviewing-directive-code/anti-patterns.md +382 -0
  50. package/skills/reviewing-directive-code/api-skeleton.md +5 -0
  51. package/skills/reviewing-directive-code/core-patterns.md +240 -0
  52. package/skills/reviewing-directive-code/examples.md +463 -0
  53. package/skills/reviewing-directive-code/naming.md +321 -0
  54. package/skills/scaffolding-directive-modules/SKILL.md +218 -0
  55. package/skills/scaffolding-directive-modules/api-skeleton.md +5 -0
  56. package/skills/scaffolding-directive-modules/core-patterns.md +240 -0
  57. package/skills/scaffolding-directive-modules/examples.md +1386 -0
  58. package/skills/scaffolding-directive-modules/naming.md +321 -0
  59. package/skills/scaffolding-directive-modules/schema-types.md +273 -0
  60. package/skills/testing-ai-systems/SKILL.md +398 -0
  61. package/skills/testing-ai-systems/ai-debug-observability.md +329 -0
  62. package/skills/testing-ai-systems/ai-mcp-rag.md +293 -0
  63. package/skills/testing-ai-systems/ai-testing-evals.md +485 -0
  64. package/skills/testing-ai-systems/api-skeleton.md +5 -0
  65. package/skills/testing-ai-systems/examples.md +1261 -0
  66. package/skills/testing-directive-code/SKILL.md +479 -0
  67. package/skills/testing-directive-code/api-skeleton.md +5 -0
  68. package/skills/testing-directive-code/examples.md +156 -0
  69. package/skills/testing-directive-code/history.md +351 -0
  70. package/skills/testing-directive-code/testing.md +412 -0
  71. package/skills/writing-directive-constraints/SKILL.md +486 -0
  72. package/skills/writing-directive-constraints/api-skeleton.md +5 -0
  73. package/skills/writing-directive-constraints/constraints.md +274 -0
  74. package/skills/writing-directive-constraints/error-boundaries.md +330 -0
  75. package/skills/writing-directive-constraints/examples.md +1361 -0
  76. package/skills/writing-directive-constraints/resolvers.md +367 -0
  77. package/skills/writing-directive-modules/SKILL.md +342 -0
  78. package/skills/writing-directive-modules/anti-patterns.md +382 -0
  79. package/skills/writing-directive-modules/api-skeleton.md +5 -0
  80. package/skills/writing-directive-modules/core-patterns.md +240 -0
  81. package/skills/writing-directive-modules/examples.md +1639 -0
  82. package/skills/writing-directive-modules/naming.md +321 -0
  83. package/skills/writing-directive-modules/schema-types.md +273 -0
@@ -0,0 +1,249 @@
1
+ ---
2
+ name: migrating-to-directive
3
+ description: "Migrate state management code from Redux, Zustand, XState, MobX, Recoil, or Jotai to Directive. Provides concept mapping, step-by-step migration patterns, and before/after code examples. Use when asked to migrate, convert, or port existing state management to Directive."
4
+ ---
5
+
6
+ # Migrating to Directive
7
+
8
+ ## Prerequisites
9
+
10
+ This skill applies when migrating TO Directive. The user should have or plan to install `@directive-run/core`: `npm install @directive-run/core`.
11
+
12
+ ## When Claude Should Use This Skill
13
+
14
+ ### Auto-Invoke Triggers
15
+ - User mentions migrating FROM Redux, Zustand, XState, MobX, Recoil, or Jotai
16
+ - User asks "how do I convert this Redux code to Directive"
17
+ - User wants to replace their state management with Directive
18
+ - User asks about Directive equivalents of concepts from other libraries
19
+ - User has existing code in another library and wants Directive version
20
+
21
+ ### Exclusions – Use a Different Skill
22
+ - User is writing Directive from scratch (no migration) → `writing-directive-modules`
23
+ - User wants to understand Directive basics → `getting-started-with-directive`
24
+
25
+ ---
26
+
27
+ ## Concept Mapping
28
+
29
+ ## Redux → Directive
30
+
31
+ | Redux | Directive | Notes |
32
+ |-------|-----------|-------|
33
+ | Store | System | `createSystem()` wraps modules |
34
+ | Slice / Reducer | Module | `createModule()` with schema + init |
35
+ | State fields | Facts | Schema keys with `t.*()` type builders |
36
+ | Selectors | Derivations | Auto-tracked, no `createSelector` needed |
37
+ | Actions | Requirements | Typed with `UPPER_SNAKE_CASE` |
38
+ | Thunks / Sagas | Resolvers | Async handlers with retry, dedup |
39
+ | Middleware | Plugins | Lifecycle hooks |
40
+ | `useSelector` | `useSelector` | From `@directive-run/react` |
41
+ | `dispatch(action)` | `system.dispatch(event)` | Or constraint auto-triggers |
42
+ | `configureStore` | `createSystem` | With plugins instead of middleware |
43
+
44
+ ### Migration Pattern
45
+
46
+ ```typescript
47
+ // BEFORE: Redux Toolkit
48
+ const counterSlice = createSlice({
49
+ name: "counter",
50
+ initialState: { value: 0, status: "idle" },
51
+ reducers: {
52
+ increment: (state) => { state.value += 1; },
53
+ decrement: (state) => { state.value -= 1; },
54
+ },
55
+ extraReducers: (builder) => {
56
+ builder.addCase(fetchCount.fulfilled, (state, action) => {
57
+ state.value = action.payload;
58
+ state.status = "loaded";
59
+ });
60
+ },
61
+ });
62
+
63
+ // AFTER: Directive
64
+ const counter = createModule("counter", {
65
+ schema: {
66
+ value: t.number(),
67
+ status: t.string<"idle" | "loading" | "loaded">(),
68
+ },
69
+ init: (facts) => {
70
+ facts.value = 0;
71
+ facts.status = "idle";
72
+ },
73
+ // Reducers become direct mutations:
74
+ // system.facts.value += 1 (no action dispatch needed)
75
+ //
76
+ // Async thunks become constraint + resolver:
77
+ constraints: {
78
+ needsData: {
79
+ when: (facts) => facts.status === "idle",
80
+ require: { type: "FETCH_COUNT" },
81
+ },
82
+ },
83
+ resolvers: {
84
+ fetchCount: {
85
+ requirement: "FETCH_COUNT",
86
+ retry: { attempts: 3, backoff: "exponential" },
87
+ resolve: async (req, context) => {
88
+ context.facts.status = "loading";
89
+ const response = await fetch("/api/count");
90
+ const data = await response.json();
91
+ context.facts.value = data.count;
92
+ context.facts.status = "loaded";
93
+ },
94
+ },
95
+ },
96
+ });
97
+ ```
98
+
99
+ ## Zustand → Directive
100
+
101
+ | Zustand | Directive | Notes |
102
+ |---------|-----------|-------|
103
+ | `create()` | `createModule()` | Module is more structured |
104
+ | State object | Schema + init | Explicit types with `t.*()` |
105
+ | Actions (set) | Direct mutation | `system.facts.x = y` |
106
+ | Selectors | Derivations | Auto-tracked |
107
+ | Middleware | Plugins | Built-in logging, devtools |
108
+ | `useStore` | `useSelector` | From React adapter |
109
+
110
+ ### Migration Pattern
111
+
112
+ ```typescript
113
+ // BEFORE: Zustand
114
+ const useStore = create((set) => ({
115
+ bears: 0,
116
+ increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
117
+ removeAllBears: () => set({ bears: 0 }),
118
+ }));
119
+
120
+ // AFTER: Directive
121
+ const bearStore = createModule("bear-store", {
122
+ schema: { bears: t.number() },
123
+ init: (facts) => { facts.bears = 0; },
124
+ });
125
+ const system = createSystem({ module: bearStore });
126
+
127
+ // Actions become direct mutations:
128
+ system.facts.bears += 1; // increasePopulation
129
+ system.facts.bears = 0; // removeAllBears
130
+ ```
131
+
132
+ ## XState → Directive
133
+
134
+ | XState | Directive | Notes |
135
+ |--------|-----------|-------|
136
+ | Machine | Module | States → facts, transitions → constraints |
137
+ | States | Fact values | `status: t.string<"idle" \| "loading">()` |
138
+ | Context | Facts | All state in schema |
139
+ | Events | Events / Requirements | `dispatch()` or auto-triggered |
140
+ | Guards | Constraint `when()` | Predicate functions |
141
+ | Actions | Resolver `resolve()` | Async handlers |
142
+ | Services | Resolvers | With retry policies |
143
+ | `useMachine` | `useSystem` | React adapter |
144
+
145
+ ### Migration Pattern
146
+
147
+ ```typescript
148
+ // BEFORE: XState
149
+ const toggleMachine = createMachine({
150
+ id: "toggle",
151
+ initial: "inactive",
152
+ states: {
153
+ inactive: { on: { TOGGLE: "active" } },
154
+ active: { on: { TOGGLE: "inactive" } },
155
+ },
156
+ });
157
+
158
+ // AFTER: Directive
159
+ const toggle = createModule("toggle", {
160
+ schema: {
161
+ status: t.string<"active" | "inactive">(),
162
+ },
163
+ init: (facts) => { facts.status = "inactive"; },
164
+ events: {
165
+ TOGGLE: (facts) => {
166
+ facts.status = facts.status === "active" ? "inactive" : "active";
167
+ },
168
+ },
169
+ });
170
+ const system = createSystem({ module: toggle });
171
+
172
+ // Trigger: system.dispatch({ type: "TOGGLE" });
173
+ ```
174
+
175
+ ## MobX → Directive
176
+
177
+ | MobX | Directive | Notes |
178
+ |------|-----------|-------|
179
+ | `observable` | Facts (schema) | Proxy-based, similar feel |
180
+ | `computed` | Derivations | Auto-tracked in both |
181
+ | `action` | Events / direct mutation | Both work |
182
+ | `reaction` | Constraints | When/require pattern |
183
+ | `autorun` | Effects | Fire-and-forget |
184
+
185
+ ## Recoil / Jotai → Directive
186
+
187
+ | Recoil/Jotai | Directive | Notes |
188
+ |--------------|-----------|-------|
189
+ | Atoms | Facts | Individual state units |
190
+ | Selectors/Derived atoms | Derivations | Auto-tracked |
191
+ | `useRecoilValue` | `useSelector` | React adapter |
192
+ | Async selectors | Constraint + Resolver | Explicit async pattern |
193
+
194
+ ---
195
+
196
+ ## Migration Steps
197
+
198
+ ## Step-by-Step Process
199
+
200
+ ```
201
+ 1. Identify state shape
202
+ → Map to schema with t.*() type builders
203
+ → Every state field → fact
204
+
205
+ 2. Identify computed values
206
+ → Map to derive {} block
207
+ → Auto-tracked, no dependency arrays needed
208
+
209
+ 3. Identify synchronous actions
210
+ → Direct mutations: system.facts.x = y
211
+ → Or events: events: { ACTION_NAME: (facts, payload) => { ... } }
212
+
213
+ 4. Identify async operations
214
+ → Constraint: when should this async work trigger?
215
+ → Resolver: how to fulfill the requirement?
216
+ → Add retry policies for network calls
217
+
218
+ 5. Identify side effects
219
+ → Map to effects {} block
220
+ → Logging, analytics, DOM sync
221
+
222
+ 6. Identify middleware
223
+ → Map to plugins [] array
224
+ → Use built-in: loggingPlugin, devtoolsPlugin, persistencePlugin
225
+
226
+ 7. Update React components
227
+ → Replace useSelector/useStore with Directive's useSelector
228
+ → Replace dispatch with direct mutation or system.dispatch
229
+ ```
230
+
231
+ ## Key Differences to Explain
232
+
233
+ ```
234
+ Redux: Action → Reducer → New State (immutable)
235
+ Directive: Mutation → Auto-constraint-check → Auto-resolve (mutable proxy)
236
+
237
+ Zustand: set() callback → New state
238
+ Directive: Direct mutation → Reactive updates
239
+
240
+ XState: Event → Guard → Transition → Action
241
+ Directive: Fact change → Constraint when() → Requirement → Resolver
242
+ ```
243
+
244
+ ## Reference Files
245
+
246
+ Supporting knowledge files loaded with this skill:
247
+ - `core-patterns.md` – Directive patterns reference
248
+ - `schema-types.md` – Type builder reference for migration
249
+ - `anti-patterns.md` – Common mistakes when migrating
@@ -0,0 +1,382 @@
1
+ # Anti-Patterns
2
+
3
+ > Covers `@directive-run/core` and `@directive-run/react` — hallucination-prone API patterns to avoid.
4
+
5
+ 19 most common mistakes when generating Directive code, ranked by AI hallucination frequency. Every code generation MUST be checked against this list.
6
+
7
+ ## 1. Unnecessary Type Casting on Facts/Derivations
8
+
9
+ ```typescript
10
+ // WRONG – schema already provides the type
11
+ const profile = system.facts.profile as ResourceState<Profile>;
12
+
13
+ // CORRECT – trust the schema
14
+ const profile = system.facts.profile;
15
+ ```
16
+
17
+ ## 2. Flat Schema (Missing facts Wrapper)
18
+
19
+ ```typescript
20
+ // WRONG – facts must be nested under schema.facts
21
+ createModule("counter", {
22
+ schema: {
23
+ phase: t.string(),
24
+ count: t.number(),
25
+ },
26
+ });
27
+
28
+ // CORRECT
29
+ createModule("counter", {
30
+ schema: {
31
+ facts: {
32
+ phase: t.string(),
33
+ count: t.number(),
34
+ },
35
+ },
36
+ });
37
+ ```
38
+
39
+ ## 3. Bare `facts.*` in Multi-Module Constraints
40
+
41
+ ```typescript
42
+ // WRONG – multi-module constraints use facts.self for own module
43
+ constraints: {
44
+ checkItems: {
45
+ when: (facts) => facts.items.length > 0,
46
+ require: { type: "PROCESS" },
47
+ },
48
+ },
49
+
50
+ // CORRECT – use facts.self.* for own module facts
51
+ constraints: {
52
+ checkItems: {
53
+ when: (facts) => facts.self.items.length > 0,
54
+ require: { type: "PROCESS" },
55
+ },
56
+ },
57
+ ```
58
+
59
+ ## 4. Nonexistent Schema Builders
60
+
61
+ ```typescript
62
+ // WRONG – t.map(), t.set(), t.promise() do not exist
63
+ schema: {
64
+ facts: {
65
+ cache: t.map<string, User>(),
66
+ tags: t.set<string>(),
67
+ pending: t.promise<Data>(),
68
+ },
69
+ },
70
+
71
+ // CORRECT – use t.object() with type parameter
72
+ schema: {
73
+ facts: {
74
+ cache: t.object<Map<string, User>>(),
75
+ tags: t.object<Set<string>>(),
76
+ pending: t.object<Promise<Data>>(),
77
+ },
78
+ },
79
+ ```
80
+
81
+ ## 5. Abbreviating `context` to `ctx`
82
+
83
+ ```typescript
84
+ // WRONG – never abbreviate context
85
+ resolve: async (req, ctx) => {
86
+ ctx.facts.status = "done";
87
+ },
88
+
89
+ // CORRECT – always spell out context
90
+ resolve: async (req, context) => {
91
+ context.facts.status = "done";
92
+ },
93
+ ```
94
+
95
+ ## 6. Flat Module Config (No schema Wrapper)
96
+
97
+ ```typescript
98
+ // WRONG – properties must be inside schema.facts
99
+ createModule("timer", {
100
+ phase: t.string(),
101
+ elapsed: t.number(),
102
+ });
103
+
104
+ // CORRECT – wrap in schema: { facts: {} }
105
+ createModule("timer", {
106
+ schema: {
107
+ facts: {
108
+ phase: t.string(),
109
+ elapsed: t.number(),
110
+ },
111
+ },
112
+ });
113
+ ```
114
+
115
+ ## 7. String-Based Event Dispatch
116
+
117
+ ```typescript
118
+ // WRONG – there is no two-argument string-keyed dispatch signature
119
+ system.dispatch("login", { token: "abc" });
120
+
121
+ // CORRECT – use the typed events accessor (preferred — autocomplete + payload typing)
122
+ system.events.login({ token: "abc" });
123
+
124
+ // ALSO VALID – the single-arg object form of dispatch() is supported when you
125
+ // need to forward a programmatically-built event. Prefer the events accessor
126
+ // for normal code.
127
+ system.dispatch({ type: "login", token: "abc" });
128
+ ```
129
+
130
+ ## 8. Direct Array/Object Mutation
131
+
132
+ ```typescript
133
+ // WRONG – proxy cannot detect in-place mutations
134
+ facts.items.push(item);
135
+ facts.config.theme = "dark";
136
+
137
+ // CORRECT – replace the entire value
138
+ facts.items = [...facts.items, item];
139
+ facts.config = { ...facts.config, theme: "dark" };
140
+ ```
141
+
142
+ ## 9. Nonexistent `useDirective` Hook
143
+
144
+ ```typescript
145
+ // WRONG – there is no useDirective hook
146
+ const state = useDirective(system);
147
+
148
+ // CORRECT – use useSelector with a selector function
149
+ const count = useSelector(system, (s) => s.facts.count);
150
+ const isLoading = useSelector(system, (s) => s.derive.isLoading);
151
+ ```
152
+
153
+ ## 10. Bracket Notation for Namespaced Facts
154
+
155
+ ```typescript
156
+ // WRONG – internal separator is not part of the public API
157
+ const status = facts["auth::status"];
158
+ const token = facts["auth_token"];
159
+
160
+ // CORRECT – use dot notation through the namespace proxy
161
+ const status = facts.auth.status;
162
+ const token = facts.auth.token;
163
+ ```
164
+
165
+ ## 11. Returning Data from Resolvers
166
+
167
+ ```typescript
168
+ // WRONG – resolvers return void, not data
169
+ resolve: async (req, context) => {
170
+ const user = await fetchUser(req.userId);
171
+
172
+ return user; // Return value is ignored
173
+ },
174
+
175
+ // CORRECT – mutate context.facts to store results
176
+ resolve: async (req, context) => {
177
+ const user = await fetchUser(req.userId);
178
+ context.facts.user = user;
179
+ },
180
+ ```
181
+
182
+ ## 12. Async Logic in `init`
183
+
184
+ ```typescript
185
+ // WRONG – init is synchronous, facts assignment only
186
+ init: async (facts) => {
187
+ const data = await fetch("/api/config");
188
+ facts.config = await data.json();
189
+ },
190
+
191
+ // CORRECT – init sets defaults; use constraints/resolvers for async work
192
+ init: (facts) => {
193
+ facts.config = null;
194
+ facts.phase = "loading";
195
+ },
196
+
197
+ constraints: {
198
+ loadConfig: {
199
+ when: (facts) => facts.config === null,
200
+ require: { type: "LOAD_CONFIG" },
201
+ },
202
+ },
203
+ ```
204
+
205
+ ## 13. Missing `settle()` After `start()`
206
+
207
+ ```typescript
208
+ // WRONG – constraints fire on start, resolvers are async
209
+ system.start();
210
+ console.log(system.facts.data); // May still be null
211
+
212
+ // CORRECT – wait for resolvers to complete
213
+ system.start();
214
+ await system.settle();
215
+ console.log(system.facts.data); // Resolved
216
+ ```
217
+
218
+ ## 14. Missing `crossModuleDeps` Declaration
219
+
220
+ ```typescript
221
+ // WRONG – accessing auth facts without declaring dependency
222
+ const dataModule = createModule("data", {
223
+ schema: { facts: { items: t.array(t.string()) } },
224
+ constraints: {
225
+ fetchWhenAuth: {
226
+ when: (facts) => facts.auth.isAuthenticated, // Type error
227
+ require: { type: "FETCH" },
228
+ },
229
+ },
230
+ });
231
+
232
+ // CORRECT – declare crossModuleDeps for type-safe cross-module access
233
+ const dataModule = createModule("data", {
234
+ schema: { facts: { items: t.array(t.string()) } },
235
+ crossModuleDeps: { auth: authSchema },
236
+ constraints: {
237
+ fetchWhenAuth: {
238
+ when: (facts) => facts.auth.isAuthenticated,
239
+ require: { type: "FETCH" },
240
+ },
241
+ },
242
+ });
243
+ ```
244
+
245
+ ## 15. String Literal for `require`
246
+
247
+ ```typescript
248
+ // WRONG – require must be an object with type property
249
+ constraints: {
250
+ check: {
251
+ when: (facts) => facts.ready,
252
+ require: "FETCH_DATA",
253
+ },
254
+ },
255
+
256
+ // CORRECT – use object form with type
257
+ constraints: {
258
+ check: {
259
+ when: (facts) => facts.ready,
260
+ require: { type: "FETCH_DATA" },
261
+ },
262
+ },
263
+ ```
264
+
265
+ ## 16. Passthrough Derivations
266
+
267
+ ```typescript
268
+ // WRONG – derivation just returns a fact value unchanged
269
+ derive: {
270
+ count: (facts) => facts.count,
271
+ },
272
+
273
+ // CORRECT – remove it, read the fact directly instead
274
+ // system.facts.count instead of system.derive.count
275
+ ```
276
+
277
+ ## 17. Deep Import Paths
278
+
279
+ ```typescript
280
+ // WRONG – internal module paths are not public API
281
+ import { createModule } from "@directive-run/core/module";
282
+ import { createSystem } from "@directive-run/core/system";
283
+
284
+ // CORRECT – import from package root
285
+ import { createModule, createSystem } from "@directive-run/core";
286
+
287
+ // Exception: plugins have their own entry point
288
+ import { loggingPlugin } from "@directive-run/core/plugins";
289
+ ```
290
+
291
+ ## 18. Async `when()` Without `deps`
292
+
293
+ ```typescript
294
+ // WRONG – async constraints need explicit deps for tracking
295
+ constraints: {
296
+ validate: {
297
+ async: true,
298
+ when: async (facts) => {
299
+ const valid = await checkRemote(facts.token);
300
+
301
+ return valid;
302
+ },
303
+ require: { type: "REFRESH_TOKEN" },
304
+ },
305
+ },
306
+
307
+ // CORRECT – add deps array for async constraints
308
+ constraints: {
309
+ validate: {
310
+ async: true,
311
+ deps: ["token"],
312
+ when: async (facts) => {
313
+ const valid = await checkRemote(facts.token);
314
+
315
+ return valid;
316
+ },
317
+ require: { type: "REFRESH_TOKEN" },
318
+ },
319
+ },
320
+ ```
321
+
322
+ ## 19. No Error Handling on Failing Resolvers
323
+
324
+ ```typescript
325
+ // WRONG – unhandled errors crash the system
326
+ resolvers: {
327
+ fetchData: {
328
+ requirement: "FETCH",
329
+ resolve: async (req, context) => {
330
+ const res = await fetch("/api/data");
331
+ context.facts.data = await res.json();
332
+ },
333
+ },
334
+ },
335
+
336
+ // CORRECT – use retry policy and/or module error boundary
337
+ resolvers: {
338
+ fetchData: {
339
+ requirement: "FETCH",
340
+ retry: { attempts: 3, backoff: "exponential" },
341
+ resolve: async (req, context) => {
342
+ const res = await fetch("/api/data");
343
+ if (!res.ok) {
344
+ throw new Error(`HTTP ${res.status}`);
345
+ }
346
+ context.facts.data = await res.json();
347
+ },
348
+ },
349
+ },
350
+
351
+ // Also set error boundary at system level
352
+ const system = createSystem({
353
+ module: myModule,
354
+ errorBoundary: {
355
+ onResolverError: "retry-later",
356
+ },
357
+ });
358
+ ```
359
+
360
+ ## Quick Reference Checklist
361
+
362
+ Before generating any Directive code, verify:
363
+
364
+ 1. Schema is nested: `schema: { facts: { ... } }` (not flat)
365
+ 2. No `as` casts when reading facts or derivations
366
+ 3. Resolver params are `(req, context)` not `(req, ctx)`
367
+ 4. `require` is an object `{ type: "..." }` not a string
368
+ 5. `init()` is synchronous
369
+ 6. Resolvers return void and mutate `context.facts`
370
+ 7. Arrays/objects replaced, not mutated in place
371
+ 8. Multi-module uses `facts.self.*` for own facts
372
+ 9. Imports from `@directive-run/core`, not deep paths
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
@@ -0,0 +1,5 @@
1
+ # API Skeleton
2
+
3
+ > Auto-generated. Do not edit.
4
+
5
+ > Source JSON not found. Build website docs first.