@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.
- package/.claude-plugin/plugin.json +6 -0
- package/LICENSE +26 -0
- package/README.md +113 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +66 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
- package/skills/README.md +9 -0
- package/skills/building-ai-agents/SKILL.md +414 -0
- package/skills/building-ai-agents/ai-adapters.md +257 -0
- package/skills/building-ai-agents/ai-agents-streaming.md +307 -0
- package/skills/building-ai-agents/ai-communication.md +304 -0
- package/skills/building-ai-agents/api-skeleton.md +5 -0
- package/skills/building-ai-agents/examples.md +849 -0
- package/skills/building-ai-orchestrators/SKILL.md +401 -0
- package/skills/building-ai-orchestrators/ai-multi-agent.md +375 -0
- package/skills/building-ai-orchestrators/ai-orchestrator.md +466 -0
- package/skills/building-ai-orchestrators/ai-tasks.md +268 -0
- package/skills/building-ai-orchestrators/api-skeleton.md +5 -0
- package/skills/building-ai-orchestrators/examples.md +1609 -0
- package/skills/building-directive-systems/SKILL.md +499 -0
- package/skills/building-directive-systems/api-skeleton.md +5 -0
- package/skills/building-directive-systems/examples.md +4149 -0
- package/skills/building-directive-systems/multi-module.md +327 -0
- package/skills/building-directive-systems/plugins.md +361 -0
- package/skills/building-directive-systems/react-adapter.md +376 -0
- package/skills/building-directive-systems/system-api.md +463 -0
- package/skills/getting-started-with-directive/SKILL.md +198 -0
- package/skills/getting-started-with-directive/api-skeleton.md +5 -0
- package/skills/getting-started-with-directive/core-patterns.md +240 -0
- package/skills/getting-started-with-directive/examples.md +87 -0
- package/skills/getting-started-with-directive/sitemap.md +202 -0
- package/skills/hardening-ai-systems/SKILL.md +377 -0
- package/skills/hardening-ai-systems/ai-budget-resilience.md +408 -0
- package/skills/hardening-ai-systems/ai-guardrails-memory.md +370 -0
- package/skills/hardening-ai-systems/ai-security.md +400 -0
- package/skills/hardening-ai-systems/api-skeleton.md +5 -0
- package/skills/hardening-ai-systems/examples.md +628 -0
- package/skills/migrating-to-directive/SKILL.md +249 -0
- package/skills/migrating-to-directive/anti-patterns.md +382 -0
- package/skills/migrating-to-directive/api-skeleton.md +5 -0
- package/skills/migrating-to-directive/core-patterns.md +240 -0
- package/skills/migrating-to-directive/examples.md +511 -0
- package/skills/migrating-to-directive/schema-types.md +273 -0
- package/skills/reviewing-directive-code/SKILL.md +232 -0
- package/skills/reviewing-directive-code/anti-patterns.md +382 -0
- package/skills/reviewing-directive-code/api-skeleton.md +5 -0
- package/skills/reviewing-directive-code/core-patterns.md +240 -0
- package/skills/reviewing-directive-code/examples.md +463 -0
- package/skills/reviewing-directive-code/naming.md +321 -0
- package/skills/scaffolding-directive-modules/SKILL.md +218 -0
- package/skills/scaffolding-directive-modules/api-skeleton.md +5 -0
- package/skills/scaffolding-directive-modules/core-patterns.md +240 -0
- package/skills/scaffolding-directive-modules/examples.md +1386 -0
- package/skills/scaffolding-directive-modules/naming.md +321 -0
- package/skills/scaffolding-directive-modules/schema-types.md +273 -0
- package/skills/testing-ai-systems/SKILL.md +398 -0
- package/skills/testing-ai-systems/ai-debug-observability.md +329 -0
- package/skills/testing-ai-systems/ai-mcp-rag.md +293 -0
- package/skills/testing-ai-systems/ai-testing-evals.md +485 -0
- package/skills/testing-ai-systems/api-skeleton.md +5 -0
- package/skills/testing-ai-systems/examples.md +1261 -0
- package/skills/testing-directive-code/SKILL.md +479 -0
- package/skills/testing-directive-code/api-skeleton.md +5 -0
- package/skills/testing-directive-code/examples.md +156 -0
- package/skills/testing-directive-code/history.md +351 -0
- package/skills/testing-directive-code/testing.md +412 -0
- package/skills/writing-directive-constraints/SKILL.md +486 -0
- package/skills/writing-directive-constraints/api-skeleton.md +5 -0
- package/skills/writing-directive-constraints/constraints.md +274 -0
- package/skills/writing-directive-constraints/error-boundaries.md +330 -0
- package/skills/writing-directive-constraints/examples.md +1361 -0
- package/skills/writing-directive-constraints/resolvers.md +367 -0
- package/skills/writing-directive-modules/SKILL.md +342 -0
- package/skills/writing-directive-modules/anti-patterns.md +382 -0
- package/skills/writing-directive-modules/api-skeleton.md +5 -0
- package/skills/writing-directive-modules/core-patterns.md +240 -0
- package/skills/writing-directive-modules/examples.md +1639 -0
- package/skills/writing-directive-modules/naming.md +321 -0
- package/skills/writing-directive-modules/schema-types.md +273 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# Core Patterns
|
|
2
|
+
|
|
3
|
+
> Covers `@directive-run/core` — modules, facts, derivations, effects, events, and the constraint-resolver loop.
|
|
4
|
+
|
|
5
|
+
How to think about building with Directive: modules, systems, and the constraint-resolver pattern.
|
|
6
|
+
|
|
7
|
+
## Decision Tree: "Where does this logic go?"
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
User wants to...
|
|
11
|
+
├── Store state → schema.facts + init()
|
|
12
|
+
├── Compute derived values → schema.derivations + derive
|
|
13
|
+
├── React to state changes → effects
|
|
14
|
+
├── Trigger side effects when conditions are met → constraints + resolvers
|
|
15
|
+
├── Handle user actions → schema.events + events handlers
|
|
16
|
+
└── Coordinate multiple modules → createSystem({ modules: {} })
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Module Shape (Canonical Object Syntax)
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// CORRECT – full module definition
|
|
23
|
+
import { createModule, t } from "@directive-run/core";
|
|
24
|
+
|
|
25
|
+
const myModule = createModule("name", {
|
|
26
|
+
schema: {
|
|
27
|
+
facts: {
|
|
28
|
+
count: t.number(),
|
|
29
|
+
phase: t.string<"idle" | "loading" | "done">(),
|
|
30
|
+
user: t.object<{ id: string; name: string } | null>(),
|
|
31
|
+
},
|
|
32
|
+
derivations: {
|
|
33
|
+
isLoading: t.boolean(),
|
|
34
|
+
displayName: t.string(),
|
|
35
|
+
},
|
|
36
|
+
events: {
|
|
37
|
+
increment: {},
|
|
38
|
+
setUser: { user: t.object<{ id: string; name: string }>() },
|
|
39
|
+
},
|
|
40
|
+
requirements: {
|
|
41
|
+
FETCH_USER: { userId: t.string() },
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
init: (facts) => {
|
|
46
|
+
facts.count = 0;
|
|
47
|
+
facts.phase = "idle";
|
|
48
|
+
facts.user = null;
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
derive: {
|
|
52
|
+
isLoading: (facts) => facts.phase === "loading",
|
|
53
|
+
displayName: (facts) => {
|
|
54
|
+
if (!facts.user) {
|
|
55
|
+
return "Guest";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return facts.user.name;
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
effects: {
|
|
63
|
+
logPhase: {
|
|
64
|
+
run: (facts, prev) => {
|
|
65
|
+
if (prev?.phase !== facts.phase) {
|
|
66
|
+
console.log(`Phase: ${facts.phase}`);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
constraints: {
|
|
73
|
+
fetchWhenReady: {
|
|
74
|
+
when: (facts) => facts.phase === "idle" && facts.count > 0,
|
|
75
|
+
require: (facts) => ({ type: "FETCH_USER", userId: "user-1" }),
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
resolvers: {
|
|
80
|
+
fetchUser: {
|
|
81
|
+
requirement: "FETCH_USER",
|
|
82
|
+
resolve: async (req, context) => {
|
|
83
|
+
context.facts.phase = "loading";
|
|
84
|
+
const res = await fetch(`/api/users/${req.userId}`);
|
|
85
|
+
const data = await res.json();
|
|
86
|
+
context.facts.user = data;
|
|
87
|
+
context.facts.phase = "done";
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
events: {
|
|
93
|
+
increment: (facts) => {
|
|
94
|
+
facts.count += 1;
|
|
95
|
+
},
|
|
96
|
+
setUser: (facts, payload) => {
|
|
97
|
+
facts.user = payload.user;
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## System Creation
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { createSystem } from "@directive-run/core";
|
|
107
|
+
import { loggingPlugin, devtoolsPlugin } from "@directive-run/core/plugins";
|
|
108
|
+
|
|
109
|
+
// Single module – direct access: system.facts.count
|
|
110
|
+
const system = createSystem({
|
|
111
|
+
module: myModule,
|
|
112
|
+
plugins: [loggingPlugin(), devtoolsPlugin()],
|
|
113
|
+
history: { maxSnapshots: 100 },
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Multi-module – namespaced access: system.facts.auth.token
|
|
117
|
+
const system = createSystem({
|
|
118
|
+
modules: { auth: authModule, cart: cartModule },
|
|
119
|
+
plugins: [devtoolsPlugin()],
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Lifecycle
|
|
123
|
+
system.start();
|
|
124
|
+
await system.settle(); // Wait for all resolvers to complete
|
|
125
|
+
// ... use the system ...
|
|
126
|
+
system.stop();
|
|
127
|
+
system.destroy();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Decision Tree: "User says 'fetch data when authenticated'"
|
|
131
|
+
|
|
132
|
+
WRONG thinking: "I'll put the fetch call in a resolver that checks auth."
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// WRONG – resolver doing condition checking + data fetching
|
|
136
|
+
resolvers: {
|
|
137
|
+
fetchData: {
|
|
138
|
+
requirement: "FETCH_DATA",
|
|
139
|
+
resolve: async (req, context) => {
|
|
140
|
+
if (!context.facts.isAuthenticated) {
|
|
141
|
+
return; // Resolver should not check conditions
|
|
142
|
+
}
|
|
143
|
+
const data = await fetch("/api/data");
|
|
144
|
+
context.facts.data = await data.json();
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
CORRECT thinking: "Constraint declares WHEN, resolver declares HOW."
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// CORRECT – constraint declares the need, resolver fulfills it
|
|
154
|
+
constraints: {
|
|
155
|
+
fetchWhenAuthenticated: {
|
|
156
|
+
when: (facts) => facts.isAuthenticated && !facts.data,
|
|
157
|
+
require: { type: "FETCH_DATA" },
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
resolvers: {
|
|
162
|
+
fetchData: {
|
|
163
|
+
requirement: "FETCH_DATA",
|
|
164
|
+
resolve: async (req, context) => {
|
|
165
|
+
const data = await fetch("/api/data");
|
|
166
|
+
context.facts.data = await data.json();
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Reading System State
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// Facts – mutable state
|
|
176
|
+
system.facts.count = 5;
|
|
177
|
+
const val = system.facts.count;
|
|
178
|
+
|
|
179
|
+
// Derivations – read-only computed values
|
|
180
|
+
const loading = system.derive.isLoading;
|
|
181
|
+
|
|
182
|
+
// Events – dispatch user actions
|
|
183
|
+
system.events.increment();
|
|
184
|
+
system.events.setUser({ user: { id: "1", name: "Alice" } });
|
|
185
|
+
|
|
186
|
+
// Subscribe to changes
|
|
187
|
+
const unsub = system.subscribe(["count", "isLoading"], () => {
|
|
188
|
+
console.log(system.facts.count, system.derive.isLoading);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Watch individual values
|
|
192
|
+
system.watch("count", (newVal, oldVal) => {
|
|
193
|
+
console.log(`Count: ${oldVal} -> ${newVal}`);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Wait for a condition
|
|
197
|
+
await system.when((facts) => facts.phase === "done");
|
|
198
|
+
await system.when((facts) => facts.phase === "done", { timeout: 5000 });
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Schema Patterns
|
|
202
|
+
|
|
203
|
+
Only `facts` is required in the schema. Other sections are optional:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// Minimal module – facts only
|
|
207
|
+
const minimal = createModule("minimal", {
|
|
208
|
+
schema: {
|
|
209
|
+
facts: { count: t.number() },
|
|
210
|
+
},
|
|
211
|
+
init: (facts) => {
|
|
212
|
+
facts.count = 0;
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Type assertion pattern (alternative to t.* builders)
|
|
217
|
+
const typed = createModule("typed", {
|
|
218
|
+
schema: {
|
|
219
|
+
facts: {} as { count: number; name: string },
|
|
220
|
+
derivations: {} as { doubled: number },
|
|
221
|
+
},
|
|
222
|
+
init: (facts) => {
|
|
223
|
+
facts.count = 0;
|
|
224
|
+
facts.name = "";
|
|
225
|
+
},
|
|
226
|
+
derive: {
|
|
227
|
+
doubled: (facts) => facts.count * 2,
|
|
228
|
+
},
|
|
229
|
+
});
|
|
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
|