@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,321 @@
1
+ # Naming Conventions
2
+
3
+ > Covers all `@directive-run/*` packages — terminology, parameter names, return-style rules.
4
+
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
+
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
+
9
+ ## Coming from another library? Start here
10
+
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. |
26
+
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.
28
+
29
+ ## Canonical terms (non-negotiable for code Directive ships)
30
+
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.
60
+
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
70
+
71
+ ### `req` = requirement (NOT request)
72
+
73
+ The `req` parameter in resolvers and constraint `key()` functions is short for **requirement** — the object emitted by a constraint's `require` property.
74
+
75
+ ```typescript
76
+ // CORRECT — req is a requirement
77
+ resolvers: {
78
+ fetchUser: {
79
+ requirement: "FETCH_USER",
80
+ key: (req) => `fetch-${req.userId}`,
81
+ resolve: async (req, context) => {
82
+ // req.type === "FETCH_USER"
83
+ const user = await fetchUser(req.userId);
84
+ context.facts.user = user;
85
+ },
86
+ },
87
+ },
88
+
89
+ // WRONG — never "request" or "r"
90
+ resolve: async (request, context) => { /* ... */ },
91
+ resolve: async (r, context) => { /* ... */ },
92
+ ```
93
+
94
+ ### `context` is never abbreviated
95
+
96
+ ```typescript
97
+ // CORRECT
98
+ resolve: async (req, context) => {
99
+ context.facts.status = "loaded";
100
+ context.signal; // AbortSignal
101
+ context.snapshot(); // facts snapshot
102
+ },
103
+
104
+ // WRONG — never abbreviate to ctx
105
+ resolve: async (req, ctx) => { /* ... */ },
106
+ ```
107
+
108
+ ## Return style
109
+
110
+ ### Braces for `if` blocks with `return` (NOT for arrow expressions)
111
+
112
+ The brace rule applies to control-flow blocks — not to arrow-expression bodies.
113
+
114
+ **Arrow expressions** (single-line derivations, predicates, computed requirements): the concise form is preferred. No braces, no explicit `return`.
115
+
116
+ ```typescript
117
+ // CORRECT — single-line arrow expressions stay concise
118
+ derive: {
119
+ isReady: (facts) => facts.phase === "ready",
120
+ greeting: (facts) => `Hi, ${facts.name}!`,
121
+ },
122
+
123
+ constraints: {
124
+ check: {
125
+ when: (facts) => facts.count > 10,
126
+ require: { type: "PROCESS" },
127
+ },
128
+ },
129
+ ```
130
+
131
+ **Control-flow statements** (`if`, `for`, `while`): braces required, even for single-line bodies. Single-line `if (x) return y` shapes are never used.
132
+
133
+ ```typescript
134
+ // WRONG — single-line if return
135
+ if (facts.user) return "ready";
136
+
137
+ // CORRECT — always wrap the body in braces
138
+ if (facts.user) {
139
+ return "ready";
140
+ }
141
+ ```
142
+
143
+ ### Blank line before `return`
144
+
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.
146
+
147
+ ```typescript
148
+ // CORRECT — blank line before return when code precedes it
149
+ function getStatus(facts) {
150
+ const phase = facts.phase;
151
+ const hasUser = facts.user !== null;
152
+
153
+ return phase === "ready" && hasUser;
154
+ }
155
+
156
+ // CORRECT — no blank line when return is first statement
157
+ function isReady(facts) {
158
+ return facts.phase === "ready";
159
+ }
160
+
161
+ // CORRECT — blank line after brace-style return block
162
+ function process(facts) {
163
+ if (!facts.ready) {
164
+ return null;
165
+ }
166
+
167
+ const result = computeResult(facts);
168
+
169
+ return result;
170
+ }
171
+ ```
172
+
173
+ ## Multi-line code formatting
174
+
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.
176
+
177
+ ```typescript
178
+ // WRONG — properties crammed on one line
179
+ schema: {
180
+ facts: { phase: t.string(), count: t.number() },
181
+ requirements: { FETCH_USER: { id: t.string() }, RESET: {} },
182
+ },
183
+
184
+ // CORRECT — one property per line, always expanded
185
+ schema: {
186
+ facts: {
187
+ phase: t.string(),
188
+ count: t.number(),
189
+ },
190
+ requirements: {
191
+ FETCH_USER: {
192
+ id: t.string(),
193
+ },
194
+ RESET: {},
195
+ },
196
+ },
197
+
198
+ // WRONG — statements crammed on one line
199
+ init: (facts) => { facts.phase = "idle"; facts.count = 0; },
200
+
201
+ // CORRECT — one statement per line
202
+ init: (facts) => {
203
+ facts.phase = "idle";
204
+ facts.count = 0;
205
+ },
206
+ ```
207
+
208
+ Single-expression arrows (no braces) are fine on one line. Empty objects `{}` are fine inline.
209
+
210
+ ```typescript
211
+ // OK — single expression, no braces
212
+ derive: {
213
+ isReady: (facts) => facts.phase === "ready",
214
+ },
215
+
216
+ // OK — empty object
217
+ RESET: {},
218
+ ```
219
+
220
+ ## Multi-module naming
221
+
222
+ ### `facts.self.*` for own module
223
+
224
+ In multi-module systems, constraints, effects, and derivations with `crossModuleDeps` receive namespaced facts. Own module facts are always at `facts.self.*`.
225
+
226
+ ```typescript
227
+ // CORRECT
228
+ constraints: {
229
+ loadWhenAuth: {
230
+ when: (facts) => facts.auth.isAuthenticated && !facts.self.loaded,
231
+ require: { type: "LOAD_DATA" },
232
+ },
233
+ },
234
+
235
+ // WRONG — bare facts.* in multi-module context
236
+ constraints: {
237
+ loadWhenAuth: {
238
+ when: (facts) => facts.isAuthenticated && !facts.loaded,
239
+ require: { type: "LOAD_DATA" },
240
+ },
241
+ },
242
+ ```
243
+
244
+ ### System-level access uses dot notation
245
+
246
+ ```typescript
247
+ // CORRECT — dot notation through namespace proxy
248
+ system.facts.auth.token;
249
+ system.facts.cart.items;
250
+ system.derive.auth.isLoggedIn;
251
+ system.events.auth.login({ token: "..." });
252
+
253
+ // WRONG — bracket notation with internal separator
254
+ system.facts["auth::token"];
255
+ system.facts["auth_token"];
256
+ ```
257
+
258
+ ## Type casting rules
259
+
260
+ ### Never cast when reading
261
+
262
+ The schema provides all types. Do not add `as` casts when reading facts or derivations from the system.
263
+
264
+ ```typescript
265
+ // CORRECT — schema provides the type
266
+ const profile = system.facts.profile;
267
+ const isReady = system.derive.isReady;
268
+
269
+ // WRONG — unnecessary cast
270
+ const profile = system.facts.profile as UserProfile;
271
+ const isReady = system.derive.isReady as boolean;
272
+ ```
273
+
274
+ ### Cast only in schema definition
275
+
276
+ Type assertions are only valid in schema definition using the `{} as {}` pattern, or via the `t.*` builders (preferred):
277
+
278
+ ```typescript
279
+ // CORRECT — cast in schema definition
280
+ schema: {
281
+ facts: {} as { profile: UserProfile; settings: AppSettings },
282
+ derivations: {} as { displayName: string },
283
+ },
284
+
285
+ // PREFERRED — t.* builders
286
+ schema: {
287
+ facts: {
288
+ profile: t.object<UserProfile>(),
289
+ settings: t.object<AppSettings>(),
290
+ },
291
+ derivations: {
292
+ displayName: t.string(),
293
+ },
294
+ },
295
+ ```
296
+
297
+ ## Terminology quick reference
298
+
299
+ Two-way lookup. Search the term you know.
300
+
301
+ | Directive term | Cross-paradigm aliases (use these to search) |
302
+ |---|---|
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)
@@ -0,0 +1,218 @@
1
+ ---
2
+ name: scaffolding-directive-modules
3
+ description: "Generate Directive module scaffolds with schema, init, derivations, constraints, resolvers, and matching test files. Use when asked to scaffold, generate, or create a new module from scratch, or when the user describes a feature and wants the boilerplate created."
4
+ ---
5
+
6
+ # Scaffolding Directive Modules
7
+
8
+ ## Prerequisites
9
+
10
+ This skill applies when the project uses `@directive-run/core`. If not found in `package.json`, suggest installing it: `npm install @directive-run/core`.
11
+
12
+ ## When Claude Should Use This Skill
13
+
14
+ ### Auto-Invoke Triggers
15
+ - User asks to "scaffold a module" or "generate a module"
16
+ - User describes a feature and wants boilerplate created
17
+ - User asks for a "starter" or "template" for a Directive module
18
+ - User wants to create a module with tests in one step
19
+
20
+ ### Exclusions – Use a Different Skill
21
+ - User wants to understand Directive concepts → `getting-started-with-directive`
22
+ - User has existing code and wants patterns guidance → `writing-directive-modules`
23
+ - User wants to review existing code → `reviewing-directive-code`
24
+
25
+ ---
26
+
27
+ ## Module Scaffold Template
28
+
29
+ ## Step 1: Identify the Domain
30
+
31
+ Ask the user (or infer from context):
32
+ 1. What is the module managing? (e.g., "user authentication", "shopping cart")
33
+ 2. What state does it track? (e.g., "login status, user profile, tokens")
34
+ 3. What actions should happen automatically? (e.g., "redirect when not logged in", "fetch profile on login")
35
+
36
+ ## Step 2: Generate Module
37
+
38
+ ```typescript
39
+ import { createModule, t } from "@directive-run/core";
40
+
41
+ // Module: {module-name}
42
+ // Purpose: {one-line description}
43
+
44
+ export const {camelCaseName} = createModule("{kebab-case-name}", {
45
+ schema: {
46
+ // State – all facts must have type builders
47
+ // {factName}: t.{type}(),
48
+ },
49
+
50
+ init: (facts) => {
51
+ // Set ALL schema keys to sensible defaults
52
+ // No async work, no side effects
53
+ },
54
+
55
+ derive: {
56
+ // Computed values – pure functions, auto-tracked
57
+ // {derivedName}: (facts) => {computation},
58
+ // Composition: {name}: (facts, derived) => derived.other && facts.x,
59
+ },
60
+
61
+ constraints: {
62
+ // Business rules: when X is true, require Y
63
+ // {constraintName}: {
64
+ // when: (facts) => {condition},
65
+ // require: { type: "REQUIREMENT_TYPE", ...payload },
66
+ // },
67
+ },
68
+
69
+ resolvers: {
70
+ // Async handlers for requirements
71
+ // {resolverName}: {
72
+ // requirement: "REQUIREMENT_TYPE",
73
+ // resolve: async (req, context) => {
74
+ // // Fulfill the requirement
75
+ // },
76
+ // },
77
+ },
78
+ });
79
+ ```
80
+
81
+ ## Step 3: Generate Test File
82
+
83
+ ```typescript
84
+ import { describe, it, expect } from "vitest";
85
+ import { createTestSystem } from "@directive-run/core/testing";
86
+ import { {camelCaseName} } from "./{kebab-case-name}";
87
+
88
+ describe("{kebab-case-name}", () => {
89
+ function createTest() {
90
+ return createTestSystem({ module: {camelCaseName} });
91
+ }
92
+
93
+ describe("initialization", () => {
94
+ it("sets default values", () => {
95
+ const system = createTest();
96
+ // expect(system.facts.{fact}).toBe({default});
97
+ });
98
+ });
99
+
100
+ describe("derivations", () => {
101
+ it("computes {derivedName}", () => {
102
+ const system = createTest();
103
+ // system.facts.{fact} = {value};
104
+ // expect(system.derive.{derivedName}).toBe({expected});
105
+ });
106
+ });
107
+
108
+ describe("constraints + resolvers", () => {
109
+ it("triggers {requirement} when {condition}", async () => {
110
+ const system = createTest();
111
+ // system.facts.{fact} = {trigger value};
112
+ // await system.settle();
113
+ // expect(system.facts.{result}).toBe({expected});
114
+ });
115
+ });
116
+ });
117
+ ```
118
+
119
+ ## Scaffold Decision Tree
120
+
121
+ ```
122
+ What kind of module?
123
+
124
+ ├── Simple state container (no async)
125
+ │ → schema + init + derive
126
+ │ → Skip constraints/resolvers
127
+ │ → Example: counter, feature-flags
128
+
129
+ ├── Data-fetching module
130
+ │ → schema includes loading/error/data states
131
+ │ → Constraint triggers fetch when needed
132
+ │ → Resolver fetches with retry policy
133
+ │ → Example: dashboard-loader, auth-flow
134
+
135
+ ├── Form/validation module
136
+ │ → schema for field values + validation state
137
+ │ → Constraints check validity rules
138
+ │ → Resolver submits form data
139
+ │ → Example: contact-form, form-wizard
140
+
141
+ ├── Multi-module coordination
142
+ │ → Multiple modules + crossModuleDeps
143
+ │ → createSystem({ modules: { a, b } })
144
+ │ → Example: multi-module, permissions
145
+
146
+ └── AI orchestrator module
147
+ │ → Use createAgentOrchestrator or createMultiAgentOrchestrator
148
+ │ → See building-ai-orchestrators skill
149
+ ```
150
+
151
+ ## Common Schema Patterns
152
+
153
+ ### Loading State
154
+
155
+ ```typescript
156
+ schema: {
157
+ status: t.string<"idle" | "loading" | "success" | "error">(),
158
+ data: t.object<DataType | null>(),
159
+ error: t.string<string | null>(),
160
+ },
161
+ init: (facts) => {
162
+ facts.status = "idle";
163
+ facts.data = null;
164
+ facts.error = null;
165
+ },
166
+ ```
167
+
168
+ ### Resource State (Generic)
169
+
170
+ ```typescript
171
+ schema: {
172
+ resource: t.object<ResourceState<T>>(),
173
+ },
174
+ // Where ResourceState<T> = { status, data, error, lastFetched }
175
+ ```
176
+
177
+ ### Authentication
178
+
179
+ ```typescript
180
+ schema: {
181
+ isAuthenticated: t.boolean(),
182
+ user: t.object<User | null>(),
183
+ token: t.string<string | null>(),
184
+ loginError: t.string<string | null>(),
185
+ },
186
+ ```
187
+
188
+ ### Pagination
189
+
190
+ ```typescript
191
+ schema: {
192
+ items: t.array<Item>(),
193
+ page: t.number(),
194
+ pageSize: t.number(),
195
+ total: t.number(),
196
+ hasMore: t.boolean(),
197
+ },
198
+ ```
199
+
200
+ ## Naming Rules (Enforced)
201
+
202
+ ```
203
+ Module variable: camelCase const userAuth = createModule(...)
204
+ Module string: kebab-case createModule("user-auth", ...)
205
+ Fact keys: camelCase isLoggedIn, userName
206
+ Derivation keys: camelCase canEdit, isAdmin
207
+ Constraint keys: camelCase enforceLogin, requireProfile
208
+ Resolver keys: camelCase fetchProfile, submitLogin
209
+ Requirement types: UPPER_SNAKE "FETCH_PROFILE", "SUBMIT_LOGIN"
210
+ Test describe: kebab-case describe("user-auth", ...)
211
+ ```
212
+
213
+ ## Reference Files
214
+
215
+ Supporting knowledge files loaded with this skill:
216
+ - `core-patterns.md` – Patterns and API reference
217
+ - `schema-types.md` – Type builders and schema patterns
218
+ - `naming.md` – Naming conventions
@@ -0,0 +1,5 @@
1
+ # API Skeleton
2
+
3
+ > Auto-generated. Do not edit.
4
+
5
+ > Source JSON not found. Build website docs first.