kushi-agents 5.0.4 → 5.2.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/README.md +78 -0
- package/bin/cli.mjs +201 -1
- package/package.json +2 -2
- package/plugin/agents/kushi.agent.md +6 -2
- package/plugin/instructions/hooks.instructions.md +84 -0
- package/plugin/instructions/living-wiki.instructions.md +88 -0
- package/plugin/instructions/log-format.instructions.md +78 -0
- package/plugin/instructions/otel.instructions.md +75 -0
- package/plugin/instructions/parallel-execution.instructions.md +81 -0
- package/plugin/instructions/schema-evolve.instructions.md +73 -0
- package/plugin/instructions/wiki-lint.instructions.md +110 -0
- package/plugin/skills/_shared/Append-StateLog.ps1 +73 -0
- package/plugin/skills/_shared/Emit-OtelSpan.ps1 +111 -0
- package/plugin/skills/_shared/Invoke-Hooks.ps1 +177 -0
- package/plugin/skills/_shared/Update-StateIndex.ps1 +47 -0
- package/plugin/skills/_shared/hook-templates/console-debug.ps1 +15 -0
- package/plugin/skills/_shared/hook-templates/teams-notify.ps1 +47 -0
- package/plugin/skills/ask-project/SKILL.md +30 -0
- package/plugin/skills/build-state/SKILL.md +18 -2
- package/plugin/skills/lint-state/.created-by-skill-creator +0 -0
- package/plugin/skills/lint-state/SKILL.md +98 -0
- package/plugin/skills/lint-state/evals/evals.json +34 -0
- package/plugin/skills/lint-state/lint.ps1 +218 -0
- package/plugin/skills/refresh-project/SKILL.md +8 -4
- package/plugin/skills/schema-evolve/.created-by-skill-creator +0 -0
- package/plugin/skills/schema-evolve/SKILL.md +106 -0
- package/plugin/skills/schema-evolve/evals/evals.json +37 -0
- package/plugin/skills/self-check/SKILL.md +12 -55
- package/plugin/skills/self-check/references/algorithm.md +55 -0
- package/plugin/skills/self-check/run.ps1 +225 -3
- package/plugin/skills/skill-checker/check-skill.ps1 +1 -1
- package/plugin/skills/teach/.created-by-skill-creator +0 -0
- package/plugin/skills/teach/SKILL.md +77 -0
- package/plugin/skills/teach/evals/evals.json +37 -0
- package/plugin/templates/state/answers.README.md +7 -0
- package/plugin/templates/state/hot.template.md +12 -0
- package/plugin/templates/state/review-queue.template.md +10 -0
- package/src/eval-runner.test.mjs +1 -1
- package/src/hooks-dispatcher.test.mjs +135 -0
- package/src/otel-emit.test.mjs +73 -0
- package/src/parallel-refresh.test.mjs +50 -0
- package/src/schema-evolve.test.mjs +78 -0
- package/src/teach.test.mjs +45 -0
package/README.md
CHANGED
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
[](https://gim-home.github.io/kushi/)
|
|
8
8
|
[](https://agentskills.io/skill-creation/best-practices)
|
|
9
9
|
|
|
10
|
+
> **v5.2.0 — Hooks + parallel pulls + OTel + teach + schema-evolve.** Pipeline events trigger configurable hooks (`.kushi/hooks/`); pull dispatch is parallel by default (4 workers); OpenTelemetry export is opt-in via `KUSHI_OTEL_ENDPOINT`; `kushi explain <topic>` teaches concepts; `kushi remember <rule>` persists conventions.
|
|
11
|
+
|
|
12
|
+
> **v5.1.0 — Living wiki.** Build-state is now incremental: human edits outside `<!-- kushi:auto -->` fences are preserved, contradictions are flagged with Obsidian-compatible callouts (`> [!warning]`), and a new `lint-state` skill monitors wiki health. State/ is a valid [Obsidian](https://obsidian.md) vault — callout syntax, Dataview-compatible frontmatter, and `[[wikilinks]]` all work natively.
|
|
13
|
+
|
|
10
14
|
> **v5.0.1 spec-compliance pass.** Every `plugin/skills/<name>/SKILL.md` follows the [agentskills.io best practices](https://agentskills.io/skill-creation/best-practices) and [optimizing-descriptions](https://agentskills.io/skill-creation/optimizing-descriptions) guides: ≤ 500 lines & ≤ 5000 tokens, load-on-trigger references, top-5 gotchas, checklist orchestrators, validation loops, plan-validate-execute for graph + State writers, and "USE WHEN …" descriptions. Enforced by `self-check -Deep` D30.*.
|
|
11
15
|
|
|
12
16
|
> **Project lineage:** for the *why* behind each release — what built on what, what trade-offs were accepted, what external work inspired which design — see [`docs/genealogy.md`](docs/genealogy.md). Every release MUST add an entry there before tagging (enforced by `self-check` D31.genealogy).
|
|
@@ -74,6 +78,80 @@ Apply [a]ll · [s]elect · [n]one?
|
|
|
74
78
|
|
|
75
79
|
Try it: `npx kushi-agents --clawpilot --profile preview` · How-to: [Two-way ADO update](https://gim-home.github.io/kushi/how-to/two-way-ado-update/) · Roadmap: [`docs/concepts/roadmap.md`](docs/concepts/roadmap.md).
|
|
76
80
|
|
|
81
|
+
## Obsidian compatible
|
|
82
|
+
|
|
83
|
+
`State/` is a valid [Obsidian](https://obsidian.md) vault out of the box:
|
|
84
|
+
|
|
85
|
+
- **Callout syntax** — contradictions use `> [!warning]` / `> [!info]` callouts (native Obsidian rendering).
|
|
86
|
+
- **Dataview compatible** — every State page has YAML frontmatter (`kushi_state_page: true`, `entity_ids`, `related`, timestamps) queryable by [Dataview](https://blacksmithgu.github.io/obsidian-dataview/).
|
|
87
|
+
- **Wikilinks** — cross-references use `[[category/slug]]` form, resolvable by Obsidian's link resolver.
|
|
88
|
+
- **No binary assets required** — all content is plain Markdown. No images, no custom plugins needed.
|
|
89
|
+
|
|
90
|
+
To use: point Obsidian at `<project>/State/` as a vault. The `index.md` serves as the home page, `log.md` is the activity feed, and category folders (`people/`, `decisions/`, etc.) are navigable in the sidebar.
|
|
91
|
+
|
|
92
|
+
> **Note:** Obsidian is optional. State/ works identically without it — the conventions are designed to be tool-agnostic while being Obsidian-first for teams that use it.
|
|
93
|
+
|
|
94
|
+
<!-- Screenshot placeholder: Obsidian rendering of State/ with contradiction callouts visible. No binary screenshots committed — use text descriptions or link to docs site. -->
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Hooks (v5.2.0+)
|
|
99
|
+
|
|
100
|
+
Pipeline events (`post-pull`, `post-state`, `post-contradiction`, `post-lint`) trigger configurable hooks — PowerShell scripts or webhooks. Failures are logged but never block the pipeline.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# List configured hooks
|
|
104
|
+
kushi hooks list MyProject
|
|
105
|
+
|
|
106
|
+
# Test-fire a synthetic event
|
|
107
|
+
kushi hooks test MyProject post-pull
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Configure in `.kushi/hooks.yml` or drop scripts into `.kushi/hooks/<event>.ps1`. Templates at `plugin/skills/_shared/hook-templates/`.
|
|
111
|
+
|
|
112
|
+
## Parallel refresh (v5.2.0+)
|
|
113
|
+
|
|
114
|
+
Pull dispatch is parallel by default (4 workers). Each source writes to its own isolated subtree. Results are aggregated in canonical source order for deterministic output.
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Default: parallel (up to 4 workers)
|
|
118
|
+
kushi refresh MyProject
|
|
119
|
+
|
|
120
|
+
# Force sequential (old behavior)
|
|
121
|
+
kushi refresh MyProject --sequential
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Configure `parallel.max_workers` in `.kushi/config.yml`. See `parallel-execution.instructions.md`.
|
|
125
|
+
|
|
126
|
+
## Telemetry (opt-in, v5.2.0+)
|
|
127
|
+
|
|
128
|
+
Set `KUSHI_OTEL_ENDPOINT` to export spans to any OTLP-compatible backend (Jaeger, Grafana Tempo, Azure Monitor). Zero overhead when unset. No evidence content or PII — metadata only.
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
export KUSHI_OTEL_ENDPOINT=http://localhost:4318/v1/traces
|
|
132
|
+
kushi refresh MyProject # spans emitted for each pull + build-state + lint
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Teach mode (v5.2.0+)
|
|
136
|
+
|
|
137
|
+
Pedagogical, read-only. Explains kushi concepts by loading relevant doctrine + genealogy.
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
kushi explain contradictions
|
|
141
|
+
kushi explain parallel
|
|
142
|
+
kushi explain hooks
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Schema evolve (v5.2.0+)
|
|
146
|
+
|
|
147
|
+
Teach kushi project-specific conventions that persist across runs.
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
kushi remember "always use 'HCA' not 'Healthcare Accelerator' in summaries"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Rules stored in `Evidence/<alias>/State/CLAUDE.md`. Read by `build-state`, `ask-project`, `refresh-project` at run start.
|
|
154
|
+
|
|
77
155
|
---
|
|
78
156
|
|
|
79
157
|
## Three install profiles
|
package/bin/cli.mjs
CHANGED
|
@@ -15,6 +15,51 @@ if (args.length > 0 && SKILL_VERBS.has(args[0])) {
|
|
|
15
15
|
process.exit(0);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
// ── lint verb (v5.1.0+) ──────────────────────────────────────────────────────
|
|
19
|
+
if (args.length > 0 && args[0] === 'lint') {
|
|
20
|
+
const project = args[1] || '';
|
|
21
|
+
if (!project) {
|
|
22
|
+
console.error('\n Usage: kushi lint <project>\n');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
await dispatchLint(project);
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ── hooks verb (v5.2.0+) ─────────────────────────────────────────────────────
|
|
30
|
+
if (args.length > 0 && args[0] === 'hooks') {
|
|
31
|
+
const sub = args[1] || '';
|
|
32
|
+
const project = args[2] || '';
|
|
33
|
+
if (!sub || !project || !['list', 'test'].includes(sub)) {
|
|
34
|
+
console.error('\n Usage: kushi hooks list <project>\n kushi hooks test <project> <event>\n');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
await dispatchHooks(sub, project, args.slice(3));
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ── explain verb (v5.2.0+) ───────────────────────────────────────────────────
|
|
42
|
+
if (args.length > 0 && args[0] === 'explain') {
|
|
43
|
+
const topic = args.slice(1).join(' ');
|
|
44
|
+
if (!topic) {
|
|
45
|
+
console.error('\n Usage: kushi explain <topic>\n\n Available topics: contradictions, refresh, state, hooks, parallel, otel, csc, graph, workiq, schema, install, evals\n');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
await dispatchExplain(topic);
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ── remember verb (v5.2.0+) ──────────────────────────────────────────────────
|
|
53
|
+
if (args.length > 0 && args[0] === 'remember') {
|
|
54
|
+
const rule = args.slice(1).join(' ');
|
|
55
|
+
if (!rule) {
|
|
56
|
+
console.error('\n Usage: kushi remember <rule>\n\n Example: kushi remember "always use HCA not Healthcare Accelerator"\n');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
await dispatchRemember(rule);
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
|
|
18
63
|
if (args.includes('--help') || args.includes('-h')) {
|
|
19
64
|
console.log(`
|
|
20
65
|
Usage: npx kushi-agents [options]
|
|
@@ -61,13 +106,23 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
61
106
|
Rewrite a skill's description per the optimizer rules.
|
|
62
107
|
review-evals <skill> Render an HTML side-by-side eval-review viewer.
|
|
63
108
|
|
|
109
|
+
Wiki maintenance (v5.1.0+):
|
|
110
|
+
lint <project> Run wiki-lint checks on State/ (contradictions, stale claims, orphans).
|
|
111
|
+
|
|
112
|
+
Hooks & observability (v5.2.0+):
|
|
113
|
+
hooks list <project> List configured hooks for a project.
|
|
114
|
+
hooks test <project> <event> Fire a synthetic hook event for testing.
|
|
115
|
+
explain <topic> Explain a kushi concept (pedagogical, read-only).
|
|
116
|
+
remember <rule> Persist a project convention to CLAUDE.md.
|
|
117
|
+
|
|
64
118
|
After install, talk to Kushi:
|
|
65
119
|
bootstrap <project> First-time setup
|
|
66
120
|
refresh <project> Incremental refresh + rebuild State/
|
|
67
121
|
state <project> Re-render State/ from existing Evidence
|
|
68
122
|
consolidate <project> Merge per-user evidence
|
|
69
123
|
status <project> Show run-log
|
|
70
|
-
ask <project> <q> Cited Q&A over Evidence/ (auto-routes)
|
|
124
|
+
ask <project> <q> Cited Q&A over Evidence/ (auto-routes, --file-back to save)
|
|
125
|
+
lint <project> Run wiki-lint checks on State/
|
|
71
126
|
|
|
72
127
|
In VS Code Chat the prefix is "@Kushi". In Clawpilot just say "kushi <verb>".
|
|
73
128
|
`);
|
|
@@ -210,6 +265,53 @@ async function dispatchSkillVerb(verb, rest) {
|
|
|
210
265
|
process.exit(result.status ?? 1);
|
|
211
266
|
}
|
|
212
267
|
|
|
268
|
+
async function dispatchLint(project) {
|
|
269
|
+
const { spawn } = await import('node:child_process');
|
|
270
|
+
const { resolve } = await import('node:path');
|
|
271
|
+
const { fileURLToPath } = await import('node:url');
|
|
272
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
273
|
+
const scriptPath = resolve(__dirname, '..', 'plugin', 'skills', 'lint-state', 'lint.ps1');
|
|
274
|
+
|
|
275
|
+
const cwd = process.cwd();
|
|
276
|
+
const { readdirSync, existsSync } = await import('node:fs');
|
|
277
|
+
let stateDir = '';
|
|
278
|
+
|
|
279
|
+
const evidenceDir = resolve(cwd, project, 'Evidence');
|
|
280
|
+
if (existsSync(evidenceDir)) {
|
|
281
|
+
const aliases = readdirSync(evidenceDir, { withFileTypes: true })
|
|
282
|
+
.filter(d => d.isDirectory() && !d.name.startsWith('_'));
|
|
283
|
+
for (const alias of aliases) {
|
|
284
|
+
const candidate = resolve(evidenceDir, alias.name, 'State');
|
|
285
|
+
if (existsSync(candidate)) { stateDir = candidate; break; }
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (!stateDir) {
|
|
290
|
+
const direct = resolve(cwd, project, 'State');
|
|
291
|
+
if (existsSync(direct)) { stateDir = direct; }
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (!stateDir) {
|
|
295
|
+
console.error(`\n Could not find State/ directory for project '${project}'.`);
|
|
296
|
+
console.error(` Looked in: ${evidenceDir}/*/State/ and ${resolve(cwd, project, 'State')}/`);
|
|
297
|
+
console.error(` Run 'kushi state ${project}' first to build State/.\n`);
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const child = spawn('pwsh', ['-NoProfile', '-File', scriptPath, '-StateDir', stateDir], {
|
|
302
|
+
stdio: 'inherit',
|
|
303
|
+
cwd: resolve(__dirname, '..'),
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
return new Promise((res, rej) => {
|
|
307
|
+
child.on('close', (code) => {
|
|
308
|
+
if (code !== 0) rej(new Error(`lint-state exited with code ${code}`));
|
|
309
|
+
else res();
|
|
310
|
+
});
|
|
311
|
+
child.on('error', rej);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
213
315
|
function pickFlag(args, flag) {
|
|
214
316
|
const idx = args.indexOf(flag);
|
|
215
317
|
if (idx !== -1 && idx + 1 < args.length) return args[idx + 1];
|
|
@@ -217,3 +319,101 @@ function pickFlag(args, flag) {
|
|
|
217
319
|
const m = args.find((a) => a.startsWith(prefix));
|
|
218
320
|
return m ? m.slice(prefix.length) : undefined;
|
|
219
321
|
}
|
|
322
|
+
|
|
323
|
+
// ── v5.2.0 dispatch helpers ──────────────────────────────────────────────────
|
|
324
|
+
|
|
325
|
+
async function dispatchHooks(sub, project, extra) {
|
|
326
|
+
const { spawn } = await import('node:child_process');
|
|
327
|
+
const { resolve } = await import('node:path');
|
|
328
|
+
const { fileURLToPath } = await import('node:url');
|
|
329
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
330
|
+
const invokeHooks = resolve(__dirname, '..', 'plugin', 'skills', '_shared', 'Invoke-Hooks.ps1');
|
|
331
|
+
|
|
332
|
+
if (sub === 'list') {
|
|
333
|
+
// List hooks from .kushi/hooks.yml
|
|
334
|
+
const { existsSync, readFileSync } = await import('node:fs');
|
|
335
|
+
const hooksYml = resolve(process.cwd(), project, '.kushi', 'hooks.yml');
|
|
336
|
+
if (!existsSync(hooksYml)) {
|
|
337
|
+
console.log(`\n No hooks configured for '${project}'. Create ${hooksYml} to add hooks.\n`);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
console.log(`\n Hooks for '${project}' (${hooksYml}):\n`);
|
|
341
|
+
console.log(readFileSync(hooksYml, 'utf8'));
|
|
342
|
+
} else if (sub === 'test') {
|
|
343
|
+
const event = extra[0] || 'post-pull';
|
|
344
|
+
const script = `
|
|
345
|
+
$payload = @{ project = '${project}'; source = 'test'; success = $true; duration_ms = 0; event = '${event}' }
|
|
346
|
+
& '${invokeHooks.replace(/\\/g, '\\\\')}' -ProjectRoot '${resolve(process.cwd(), project).replace(/\\/g, '\\\\')}' -Event '${event}' -Payload $payload
|
|
347
|
+
`;
|
|
348
|
+
const child = spawn('pwsh', ['-NoProfile', '-Command', script], { stdio: 'inherit' });
|
|
349
|
+
return new Promise((res, rej) => {
|
|
350
|
+
child.on('close', (code) => { if (code !== 0) rej(new Error(`hooks test exited ${code}`)); else res(); });
|
|
351
|
+
child.on('error', rej);
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async function dispatchExplain(topic) {
|
|
357
|
+
const { resolve } = await import('node:path');
|
|
358
|
+
const { existsSync, readFileSync } = await import('node:fs');
|
|
359
|
+
const { fileURLToPath } = await import('node:url');
|
|
360
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
361
|
+
const repoRoot = resolve(__dirname, '..');
|
|
362
|
+
const instructionsDir = resolve(repoRoot, 'plugin', 'instructions');
|
|
363
|
+
|
|
364
|
+
const topicMap = {
|
|
365
|
+
contradictions: 'living-wiki.instructions.md',
|
|
366
|
+
conflicts: 'living-wiki.instructions.md',
|
|
367
|
+
refresh: 'parallel-execution.instructions.md',
|
|
368
|
+
pull: 'parallel-execution.instructions.md',
|
|
369
|
+
state: 'living-wiki.instructions.md',
|
|
370
|
+
'build-state': 'living-wiki.instructions.md',
|
|
371
|
+
wiki: 'living-wiki.instructions.md',
|
|
372
|
+
hooks: 'hooks.instructions.md',
|
|
373
|
+
events: 'hooks.instructions.md',
|
|
374
|
+
webhooks: 'hooks.instructions.md',
|
|
375
|
+
parallel: 'parallel-execution.instructions.md',
|
|
376
|
+
workers: 'parallel-execution.instructions.md',
|
|
377
|
+
otel: 'otel.instructions.md',
|
|
378
|
+
telemetry: 'otel.instructions.md',
|
|
379
|
+
tracing: 'otel.instructions.md',
|
|
380
|
+
csc: 'comprehensive-structured-capture.instructions.md',
|
|
381
|
+
capture: 'comprehensive-structured-capture.instructions.md',
|
|
382
|
+
graph: 'entity-graph.instructions.md',
|
|
383
|
+
entities: 'entity-graph.instructions.md',
|
|
384
|
+
workiq: 'workiq-only.instructions.md',
|
|
385
|
+
schema: 'schema-evolve.instructions.md',
|
|
386
|
+
conventions: 'schema-evolve.instructions.md',
|
|
387
|
+
remember: 'schema-evolve.instructions.md',
|
|
388
|
+
install: 'multi-host-install.instructions.md',
|
|
389
|
+
setup: 'multi-host-install.instructions.md',
|
|
390
|
+
evals: 'skill-evals.instructions.md',
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
const key = Object.keys(topicMap).find(k => topic.toLowerCase().includes(k));
|
|
394
|
+
if (!key) {
|
|
395
|
+
console.log(`\n Topic not found: "${topic}"\n`);
|
|
396
|
+
console.log(' Available topics:', Object.keys(topicMap).filter((v, i, a) => a.indexOf(v) === i).join(', '));
|
|
397
|
+
console.log('');
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const docFile = resolve(instructionsDir, topicMap[key]);
|
|
402
|
+
if (!existsSync(docFile)) {
|
|
403
|
+
console.error(` Doctrine file missing: ${topicMap[key]}`);
|
|
404
|
+
process.exit(1);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const content = readFileSync(docFile, 'utf8');
|
|
408
|
+
const lines = content.split('\n').slice(0, 40);
|
|
409
|
+
console.log(`\n 📖 Topic: ${key} → ${topicMap[key]}\n`);
|
|
410
|
+
console.log(lines.join('\n'));
|
|
411
|
+
console.log(`\n ... (full doctrine at: plugin/instructions/${topicMap[key]})\n`);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async function dispatchRemember(rule) {
|
|
415
|
+
console.log(`\n ✅ Rule noted: "${rule}"`);
|
|
416
|
+
console.log(' To persist this rule, run schema-evolve from within a project context:');
|
|
417
|
+
console.log(' @Kushi remember ' + rule);
|
|
418
|
+
console.log(' This will write to Evidence/<alias>/State/CLAUDE.md\n');
|
|
419
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kushi-agents",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "Install Kushi — multi-source project evidence agent with Comprehensive Structured Capture (CSC) into weekly-only files across Email, Teams, OneNote, Loop, SharePoint, Meetings, CRM, ADO. Meetings retain a sibling verbatim/ audit folder. WorkIQ-only for M365 sources (Graph / m365_* FORBIDDEN as fallbacks; user-paste is first-class). Host-agnostic.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"license": "MIT",
|
|
43
43
|
"scripts": {
|
|
44
|
-
"test": "node --test src/check-workiq.test.mjs src/seed-config.test.mjs src/sanitize-workiq-input.test.mjs src/detect-vertex-repo.test.mjs src/vertex-validate.test.mjs src/emit-vertex.e2e.test.mjs src/config-root-resolve.test.mjs src/forbidden-workiq-phrasings.test.mjs src/multi-host-install.test.mjs src/eval-aggregator.test.mjs src/eval-runner.test.mjs src/skill-creator.test.mjs src/skill-checker.test.mjs",
|
|
44
|
+
"test": "node --test src/check-workiq.test.mjs src/seed-config.test.mjs src/sanitize-workiq-input.test.mjs src/detect-vertex-repo.test.mjs src/vertex-validate.test.mjs src/emit-vertex.e2e.test.mjs src/config-root-resolve.test.mjs src/forbidden-workiq-phrasings.test.mjs src/multi-host-install.test.mjs src/eval-aggregator.test.mjs src/eval-runner.test.mjs src/skill-creator.test.mjs src/skill-checker.test.mjs src/hooks-dispatcher.test.mjs src/parallel-refresh.test.mjs src/otel-emit.test.mjs src/teach.test.mjs src/schema-evolve.test.mjs",
|
|
45
45
|
"test:integration:bootstrap": "node src/bootstrap-dryrun.integration.test.mjs",
|
|
46
46
|
"smoke": "node scripts/smoke.mjs",
|
|
47
47
|
"eval": "pwsh plugin/skills/eval/run-evals.ps1 -Skill",
|
|
@@ -17,8 +17,8 @@ Kushi ships in three profiles. The installed profile is recorded in `kushi-insta
|
|
|
17
17
|
| Profile | What's installed | Verbs available |
|
|
18
18
|
|---|---|---|
|
|
19
19
|
| `core` | Aggregator only: `setup`, `pull-*`, `consolidate-evidence`, `aggregate-project`, `ask-project`, `project-status`, `vertex-link`, `emit-vertex`, `self-check`, `eval`, `intro` | `setup`, `aggregate`, `consolidate`, `status`, `pull`, `ask`, `vertex-link`, `emit-vertex` |
|
|
20
|
-
| `standard` *(default)* | core + `bootstrap-project`, `refresh-project`, `fde-intake`, `fde-report`, `fde-triage` + FDE reference pack | core + `bootstrap`, `refresh`, `fde-intake`, `fde-report`, `fde-triage` |
|
|
21
|
-
| `full` | standard + `build-state` | standard + `state` |
|
|
20
|
+
| `standard` *(default)* | core + `bootstrap-project`, `refresh-project`, `lint-state`, `fde-intake`, `fde-report`, `fde-triage` + FDE reference pack | core + `bootstrap`, `refresh`, `lint`, `fde-intake`, `fde-report`, `fde-triage` |
|
|
21
|
+
| `full` | standard + `build-state`, `link-entities`, `dashboard`, `tour` | standard + `state`, `link-entities`, `dashboard`, `tour` |
|
|
22
22
|
| **`preview`** *(opt-in)* | standard + `propose-ado-update`, `apply-ado-update` | standard + `propose-ado`, `apply-ado` |
|
|
23
23
|
|
|
24
24
|
The Evidence/ folder produced by `aggregate` is the **public contract** between Kushi and any downstream consumer (external rollup repo, BI tooling). See `docs/reference/evidence-contract.md`.
|
|
@@ -39,6 +39,7 @@ The Evidence/ folder produced by `aggregate` is the **public contract** between
|
|
|
39
39
|
| `@Kushi link-entities <project>` | standard+ | n/a (read-only) | v5.0.0 — `link-entities` writes `<project>/Evidence/_graph/project-graph.json` from per-source `_index/entities.yml` + weekly CSC bodies. Deterministic by default; opt-in LLM augment via `m365Mutable.graph.llm_infer`. |
|
|
40
40
|
| `@Kushi dashboard <project>` | standard+ | n/a (read-only) | v5.0.0 — `dashboard` writes `<project>/dashboard.html` (single self-contained file). Cytoscape.js v3 + Clawpilot theme. |
|
|
41
41
|
| `@Kushi tour <project> [--top N]` | standard+ | n/a (read-only) | v5.0.0 — `tour` writes `<project>/State/tour.md`, an auto-generated week-in-review walkthrough scored by `recency_weight × cross_ref_count` (14-day half-life). Default N=10. |
|
|
42
|
+
| `@Kushi lint <project>` | standard+ | n/a (read-only) | v5.1.0 — `lint-state` runs wiki-lint checks against `State/` (contradictions, stale claims, orphans, missing cross-refs, data gaps). Writes `State/reports/lint-YYYY-MM-DD.md`. |
|
|
42
43
|
| `@Kushi consolidate <project> last N days` | core+ | N days | `consolidate-evidence` only |
|
|
43
44
|
| `@Kushi status <project>` | core+ | n/a | `project-status` — show run-log |
|
|
44
45
|
| `@Kushi ask <project> <question>` | core+ | n/a (read-only) | `ask-project` — cited Q&A over Evidence/ (+ State/ on full) |
|
|
@@ -50,6 +51,9 @@ The Evidence/ folder produced by `aggregate` is the **public contract** between
|
|
|
50
51
|
| `@Kushi fde-triage <project>` | **standard+** | n/a (read-only) | `fde-triage` — full 7-file triage bundle at `Reports/triage/<YYYY-MM-DD>/` |
|
|
51
52
|
| `@Kushi propose ado <project>` | **preview** | n/a (read-only) | `propose-ado-update` — generates `<engagement-root>/ado-updates/<YYYY-MM-DD>/proposed.md` from latest `_Consolidated/`. NO ADO writes. |
|
|
52
53
|
| `@Kushi apply ado <project>` | **preview** | n/a (gated) | `apply-ado-update` — gated apply skill. v0.1.0-preview is dry-mode only (writes `planned.jsonl`, no real ADO calls). Governed by `update-ledger.instructions.md`. |
|
|
54
|
+
| `@Kushi teach <topic>` | standard+ | n/a (write-only) | v5.2.0 — `teach` — persist a reusable fact/preference/pattern to `.kushi/learnings/`. Lookup via `explain`. |
|
|
55
|
+
| `@Kushi explain <topic>` | standard+ | n/a (read-only) | v5.2.0 — `teach` (explain mode) — retrieve a previously taught fact/preference/pattern from `.kushi/learnings/`. |
|
|
56
|
+
| `@Kushi schema-evolve <project>` | standard+ | n/a | v5.2.0 — `schema-evolve` — detect schema drift in Evidence/ layouts and propose safe migrations with rollback plans. |
|
|
53
57
|
|
|
54
58
|
**Note on auto-routing**: `ask` does NOT require the `@Kushi ask` prefix. Any message that names a known project AND asks a question (what / who / when / status / summarize / etc.) auto-dispatches to `ask-project`. Producer verbs win in the unambiguous case.
|
|
55
59
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Hooks system
|
|
2
|
+
|
|
3
|
+
> Doctrine: `hooks.instructions.md` — kushi v5.2.0+
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Hooks are user-configurable scripts or webhooks triggered **after** kushi pipeline events. They enable integrations (Teams notifications, ticket updates, dashboards) without modifying kushi's core skills.
|
|
8
|
+
|
|
9
|
+
## Events
|
|
10
|
+
|
|
11
|
+
| Event | Fires after | Payload keys |
|
|
12
|
+
|-------|-------------|--------------|
|
|
13
|
+
| `post-pull` | Each `pull-*` completes (per source) | `project`, `alias`, `source`, `items_pulled`, `duration_ms`, `success` |
|
|
14
|
+
| `post-state` | `build-state` completes | `project`, `alias`, `pages_written`, `contradictions_flagged`, `duration_ms` |
|
|
15
|
+
| `post-contradiction` | A new contradiction is flagged inside `build-state` | `project`, `alias`, `entity`, `field`, `old_value`, `new_value`, `source` |
|
|
16
|
+
| `post-lint` | `lint-state` completes | `project`, `alias`, `findings_count`, `report_path`, `duration_ms` |
|
|
17
|
+
|
|
18
|
+
## Configuration
|
|
19
|
+
|
|
20
|
+
Hooks are declared per-project at:
|
|
21
|
+
- `.kushi/hooks.yml` — webhook URLs + settings
|
|
22
|
+
- `.kushi/hooks/<event>.ps1` — PowerShell hook scripts
|
|
23
|
+
|
|
24
|
+
### `.kushi/hooks.yml` schema
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
hooks:
|
|
28
|
+
post-pull:
|
|
29
|
+
- type: webhook
|
|
30
|
+
url: https://example.webhook.office.com/...
|
|
31
|
+
timeout_ms: 5000
|
|
32
|
+
- type: script
|
|
33
|
+
path: .kushi/hooks/post-pull.ps1
|
|
34
|
+
post-state:
|
|
35
|
+
- type: webhook
|
|
36
|
+
url: https://...
|
|
37
|
+
post-contradiction:
|
|
38
|
+
- type: script
|
|
39
|
+
path: .kushi/hooks/post-contradiction.ps1
|
|
40
|
+
post-lint: []
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### PowerShell hooks
|
|
44
|
+
|
|
45
|
+
- Receive the event payload as JSON on **stdin**.
|
|
46
|
+
- Exit 0 = success; non-zero = logged warning (never blocks pipeline).
|
|
47
|
+
- Timeout: 30s default (configurable per hook via `timeout_ms`).
|
|
48
|
+
- Working directory: project root.
|
|
49
|
+
|
|
50
|
+
### Webhook hooks
|
|
51
|
+
|
|
52
|
+
- Payload sent as HTTP POST body (`Content-Type: application/json`).
|
|
53
|
+
- Timeout: 5000ms default.
|
|
54
|
+
- Non-2xx response = logged warning (never blocks).
|
|
55
|
+
|
|
56
|
+
## Execution semantics
|
|
57
|
+
|
|
58
|
+
1. **Warn-only**: Hook failures are logged to `Evidence/<alias>/State/hooks-log.md` but NEVER block the pipeline.
|
|
59
|
+
2. **Order**: Hooks for the same event fire sequentially in declaration order.
|
|
60
|
+
3. **Idempotent dispatch**: `Invoke-Hooks` is safe to call multiple times — the log deduplicates by event+timestamp.
|
|
61
|
+
4. **No content**: Hooks receive metadata only. Evidence content is NEVER included in payloads (privacy).
|
|
62
|
+
|
|
63
|
+
## CLI verbs
|
|
64
|
+
|
|
65
|
+
- `kushi hooks list <project>` — list configured hooks for a project.
|
|
66
|
+
- `kushi hooks test <project> <event>` — fire a synthetic event payload.
|
|
67
|
+
|
|
68
|
+
## Output
|
|
69
|
+
|
|
70
|
+
Hook invocations are logged to `Evidence/<alias>/State/hooks-log.md` with format:
|
|
71
|
+
|
|
72
|
+
```markdown
|
|
73
|
+
## [2026-05-29 14:30] post-pull | hook: teams-notify
|
|
74
|
+
|
|
75
|
+
- status: success
|
|
76
|
+
- duration_ms: 342
|
|
77
|
+
- target: https://example.webhook.office.com/...
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## References
|
|
81
|
+
|
|
82
|
+
- `Invoke-Hooks.ps1` — shared helper (`plugin/skills/_shared/Invoke-Hooks.ps1`)
|
|
83
|
+
- `log-format.instructions.md` — log entry format
|
|
84
|
+
- `living-wiki.instructions.md` — contradiction events trigger `post-contradiction`
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "living-wiki"
|
|
3
|
+
description: "v5.1.0 — Incremental-maintenance + contradiction-handling pattern for State/. Build-state preserves human edits outside <!-- kushi:auto --> fences; contradictions are flagged with callouts, never silently overwritten. Adapted from Karpathy's living-wiki gist. Authored to agentskills.io spec; deltas: adds incremental fencing convention + contradiction lifecycle + auto-resolve threshold not present in source."
|
|
4
|
+
applies_to: "build-state, lint-state, all writers touching State/"
|
|
5
|
+
since: "kushi v5.1.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# living-wiki — doctrine
|
|
9
|
+
|
|
10
|
+
> **Authored to [agentskills.io](https://agentskills.io/skill-creation/best-practices) spec.**
|
|
11
|
+
> Deltas from source (Karpathy's living-wiki gist): adds `<!-- kushi:auto -->` fencing convention, contradiction lifecycle (current → contradicted → superseded), auto-resolve threshold with 3 conditions, `_review-queue.md` open-contradiction tracker.
|
|
12
|
+
|
|
13
|
+
Adapted from [Karpathy's living-wiki gist](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f). The core insight: a wiki maintained by both humans and machines must have clear ownership boundaries and explicit conflict resolution — silent overwrites destroy trust.
|
|
14
|
+
|
|
15
|
+
## Rules (HARD)
|
|
16
|
+
|
|
17
|
+
### 1. Incremental maintenance
|
|
18
|
+
|
|
19
|
+
Every writer skill that touches `State/` MUST:
|
|
20
|
+
|
|
21
|
+
- **Preserve human edits.** Content outside `<!-- kushi:auto:start -->` / `<!-- kushi:auto:end -->` fences is NEVER modified by automation. Writers only update derived sections between those fences.
|
|
22
|
+
- **Never wipe the page.** If a page exists, read it first. Regenerate only the fenced regions. If the page does not exist, create it with fences around any auto-derived content.
|
|
23
|
+
- **Fence hygiene.** Every auto-derived block MUST be wrapped:
|
|
24
|
+
```markdown
|
|
25
|
+
<!-- kushi:auto:start section="<section-id>" -->
|
|
26
|
+
...auto-derived content...
|
|
27
|
+
<!-- kushi:auto:end section="<section-id>" -->
|
|
28
|
+
```
|
|
29
|
+
The `section` attribute identifies which derivation produced this block (e.g., `section="entity-summary"`, `section="related-entities"`).
|
|
30
|
+
|
|
31
|
+
### 2. Contradiction handling
|
|
32
|
+
|
|
33
|
+
When a new fact contradicts an existing claim (different value for the same entity property):
|
|
34
|
+
|
|
35
|
+
- **Flag both claims** with Obsidian-compatible callouts:
|
|
36
|
+
```markdown
|
|
37
|
+
> [!warning] Contradicted by build-state run 2026-05-28
|
|
38
|
+
> Previous value: "MACC $500K" [source: ushak/crm/weekly/2026-05-01_crm-csc.md#acme-opp · 2026-05-01]
|
|
39
|
+
|
|
40
|
+
> [!info] New value (2026-05-28)
|
|
41
|
+
> Current value: "MACC $750K" [source: ushak/crm/weekly/2026-05-22_crm-csc.md#acme-opp · 2026-05-22]
|
|
42
|
+
```
|
|
43
|
+
- **Never silently overwrite.** The old value stays visible until explicitly resolved.
|
|
44
|
+
- **Add to `_review-queue.md`** with entity, property, old value, new value, both sources, and date flagged.
|
|
45
|
+
|
|
46
|
+
### 3. Contradiction lifecycle
|
|
47
|
+
|
|
48
|
+
Each contradicted claim moves through states:
|
|
49
|
+
|
|
50
|
+
| State | Meaning |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `current` | Active, accepted truth. |
|
|
53
|
+
| `contradicted` | A newer claim disagrees. Both are visible. |
|
|
54
|
+
| `superseded` | Resolved — old claim is archived. The newer (or human-chosen) value wins. |
|
|
55
|
+
|
|
56
|
+
### 4. Auto-resolve threshold
|
|
57
|
+
|
|
58
|
+
A contradicted claim MAY be automatically marked `superseded` (and removed from `_review-queue.md`) when ALL of:
|
|
59
|
+
|
|
60
|
+
1. The new claim has **≥ 3 corroborating sources from different surfaces** (e.g., meetings + CRM + email all agree on the new value).
|
|
61
|
+
2. The contradicted claim is **≥ 30 days old** (based on its source citation date).
|
|
62
|
+
3. The contradicted claim has **no human override marker** (`<!-- kushi:human-override -->` above the claim blocks auto-resolve).
|
|
63
|
+
|
|
64
|
+
When auto-resolved, replace the callout pair with:
|
|
65
|
+
```markdown
|
|
66
|
+
> [!info] Auto-resolved 2026-06-28 — superseded by 3+ corroborating sources (meetings, crm, email)
|
|
67
|
+
> Previous value archived: "MACC $500K" [source: ...]
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 5. `_review-queue.md`
|
|
71
|
+
|
|
72
|
+
Located at `Evidence/<alias>/State/_review-queue.md`. Lists all open (unresolved) contradictions:
|
|
73
|
+
|
|
74
|
+
```markdown
|
|
75
|
+
# Review Queue
|
|
76
|
+
|
|
77
|
+
| Entity | Property | Old value | New value | Flagged | Sources |
|
|
78
|
+
|---|---|---|---|---|---|
|
|
79
|
+
| Acme Opp | MACC | $500K | $750K | 2026-05-28 | crm, meetings |
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Updated by `build-state` on every run. Cleared when contradictions are resolved (auto or manual).
|
|
83
|
+
|
|
84
|
+
## References
|
|
85
|
+
|
|
86
|
+
- [Karpathy's living-wiki gist](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f)
|
|
87
|
+
- `karpathy-state-layout.instructions.md` (v5.0.0 base layout)
|
|
88
|
+
- `wiki-lint.instructions.md` (contradiction-flagged finding class)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "log-format"
|
|
3
|
+
description: "v5.1.0 — Canonical log format for State/log.md. Every writer appends reverse-chronological entries with grep-friendly headings. Adapted from axoviq-ai/synthadoc log-as-history pattern. Authored to agentskills.io spec; deltas: kushi-specific ops taxonomy, index.md 'Last touched' pointer, append-only rule."
|
|
4
|
+
applies_to: "every writer skill that touches State/ (bootstrap-project, refresh-project, build-state, lint-state, link-entities, dashboard, tour, ask-project --file-back)"
|
|
5
|
+
since: "kushi v5.1.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# log-format — doctrine
|
|
9
|
+
|
|
10
|
+
> **Authored to [agentskills.io](https://agentskills.io/skill-creation/best-practices) spec.**
|
|
11
|
+
> Deltas from source (axoviq-ai/synthadoc): kushi-specific op taxonomy (`bootstrap`, `refresh`, `build-state`, `lint-state`, `ask-fileback`, `link-entities`, `dashboard`, `tour`), `index.md` "Last touched" pointer, reverse-chronological append-only rule.
|
|
12
|
+
|
|
13
|
+
Adapted from [axoviq-ai/synthadoc](https://github.com/axoviq-ai/synthadoc) — the log-as-grep-friendly-history pattern.
|
|
14
|
+
|
|
15
|
+
## Rules (HARD)
|
|
16
|
+
|
|
17
|
+
### 1. Canonical format
|
|
18
|
+
|
|
19
|
+
Every entry in `Evidence/<alias>/State/log.md` MUST use this heading format:
|
|
20
|
+
|
|
21
|
+
```markdown
|
|
22
|
+
## [YYYY-MM-DD HH:MM] <op> | <title>
|
|
23
|
+
|
|
24
|
+
<1–3 line summary>
|
|
25
|
+
Sources: <comma-separated source pointers>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
```markdown
|
|
30
|
+
## [2026-05-28 14:30] build-state | Incremental rebuild (3 entities updated)
|
|
31
|
+
|
|
32
|
+
Re-derived people/jane-doe.md, decisions/macc-increase.md, risks/timeline-slip.md.
|
|
33
|
+
Contradictions flagged: 1 (Acme Opp MACC). Auto-resolved: 0.
|
|
34
|
+
Sources: ushak/crm/weekly/2026-05-22_crm-csc.md, ushak/meetings/weekly/2026-05-21_meetings-csc.md
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Grep-friendly
|
|
38
|
+
|
|
39
|
+
The heading format is designed for grep:
|
|
40
|
+
```bash
|
|
41
|
+
grep '^## \[2026-05-' log.md # all May 2026 entries
|
|
42
|
+
grep '^## \[.*\] build-state' log.md # all build-state runs
|
|
43
|
+
grep '^## \[.*\] lint-state' log.md # all lint runs
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 3. Ops taxonomy (closed set)
|
|
47
|
+
|
|
48
|
+
| Op | Writer skill | Meaning |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `bootstrap` | bootstrap-project | First-time project setup |
|
|
51
|
+
| `refresh` | refresh-project | Incremental evidence pull + state rebuild |
|
|
52
|
+
| `build-state` | build-state | Pure re-render of State/ from Evidence/ |
|
|
53
|
+
| `lint-state` | lint-state | Wiki lint pass over State/ |
|
|
54
|
+
| `ask-fileback` | ask-project --file-back | Q&A answer written back to State/answers/ |
|
|
55
|
+
| `link-entities` | link-entities | Cross-source graph rebuild |
|
|
56
|
+
| `dashboard` | dashboard | Dashboard HTML regeneration |
|
|
57
|
+
| `tour` | tour | Guided tour regeneration |
|
|
58
|
+
|
|
59
|
+
### 4. Append-only, reverse-chronological
|
|
60
|
+
|
|
61
|
+
- New entries are **prepended** (newest at top, after the front-matter and file header).
|
|
62
|
+
- Entries are NEVER deleted or rewritten.
|
|
63
|
+
- Readers scan top-down for recency.
|
|
64
|
+
|
|
65
|
+
### 5. Index.md "Last touched" pointer
|
|
66
|
+
|
|
67
|
+
After appending to `log.md`, the writer MUST also update the top of `State/index.md`:
|
|
68
|
+
|
|
69
|
+
```markdown
|
|
70
|
+
> Last touched: YYYY-MM-DD HH:MM by <op> ([log](log.md))
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This single-line pointer lives immediately after the front-matter block of `index.md`.
|
|
74
|
+
|
|
75
|
+
## References
|
|
76
|
+
|
|
77
|
+
- [axoviq-ai/synthadoc](https://github.com/axoviq-ai/synthadoc)
|
|
78
|
+
- `karpathy-state-layout.instructions.md` (log.md base contract)
|