@interleavelove/keating 0.1.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 (39) hide show
  1. package/README.md +274 -0
  2. package/bin/keating.js +31 -0
  3. package/dist/src/cli/main.js +165 -0
  4. package/dist/src/core/animation.js +372 -0
  5. package/dist/src/core/benchmark.js +238 -0
  6. package/dist/src/core/config.js +81 -0
  7. package/dist/src/core/evolution.js +224 -0
  8. package/dist/src/core/learner-state.js +88 -0
  9. package/dist/src/core/lesson-plan.js +155 -0
  10. package/dist/src/core/map.js +89 -0
  11. package/dist/src/core/paths.js +69 -0
  12. package/dist/src/core/pi-agent.js +58 -0
  13. package/dist/src/core/policy.js +53 -0
  14. package/dist/src/core/project.js +189 -0
  15. package/dist/src/core/prompt-evolution.js +337 -0
  16. package/dist/src/core/random.js +19 -0
  17. package/dist/src/core/self-improve.js +419 -0
  18. package/dist/src/core/topics.js +620 -0
  19. package/dist/src/core/types.js +1 -0
  20. package/dist/src/core/util.js +28 -0
  21. package/dist/src/core/verification.js +162 -0
  22. package/dist/src/pi/hyperteacher-extension.js +180 -0
  23. package/dist/src/runtime/pi.js +118 -0
  24. package/dist/test/animation.test.js +43 -0
  25. package/dist/test/config.test.js +36 -0
  26. package/dist/test/evolution.test.js +39 -0
  27. package/dist/test/fuzz.test.js +37 -0
  28. package/dist/test/hyperteacher-extension.test.js +122 -0
  29. package/dist/test/lesson-plan.test.js +35 -0
  30. package/dist/test/pipeline.test.js +57 -0
  31. package/dist/test/prompt-evolution.test.js +89 -0
  32. package/package.json +58 -0
  33. package/pi/prompts/bridge.md +14 -0
  34. package/pi/prompts/diagnose.md +15 -0
  35. package/pi/prompts/improve.md +39 -0
  36. package/pi/prompts/learn.md +21 -0
  37. package/pi/prompts/quiz.md +14 -0
  38. package/pi/skills/adaptive-teaching/SKILL.md +33 -0
  39. package/scripts/install/install.sh +307 -0
package/README.md ADDED
@@ -0,0 +1,274 @@
1
+ # Keating
2
+
3
+ > *"O me! O life! of the questions of these recurring,
4
+ > Of the endless trains of the faithless, of cities fill’d with the foolish,
5
+ > Of myself for ever reproaching myself, (for who more foolish than I, and who more faithless?)
6
+ > Of eyes that vainly crave the light, of the objects mean, of the struggle ever renew’d,
7
+ > Of the poor results of all, of the plodding and sordid crowds I see around me,
8
+ > Of the empty and useless years of the rest, with the rest me intertwined,
9
+ > The question, O me! so sad, recurring—What good amid these, O me, O life?
10
+ >
11
+ > Answer.
12
+ > That you are here—that life exists and identity,
13
+ > That the powerful play goes on, and you may contribute a verse."*
14
+ > -- Walt Whitman, *Leaves of Grass*
15
+
16
+ Keating exists because as AI grows more capable, the risk is not just that it replaces our tasks, but that it replaces our *voice*. We must not let technology become a surrogate for thought.
17
+
18
+ **The goal of Keating is cognitive empowerment.** It is a Pi-powered hyperteacher scaffold designed to ensure that humans remain the authors of their own understanding. It uses the most advanced models not to provide answers, but to force the rigorous reconstruction of ideas within the learner's own identity.
19
+
20
+ We use technology to ensure the "powerful play" goes on, and that every learner is equipped to contribute their own verse.
21
+
22
+ It is designed around five influences:
23
+
24
+ - `feynman` for the shell ergonomics, slash workflows, and artifact-oriented research UX.
25
+ - `pi-mono` for the runtime model: prompts, skills, and extensions instead of a forked monolith.
26
+ - `chrysalis-forge` for self-evolution, archival evaluation, and safety-gated improvement.
27
+ - `HyperAgent` for role separation between planning, execution, and verification.
28
+ - `Meta-Harness` for harness-level improvement rather than prompt-only tweaking.
29
+
30
+ ## What Exists
31
+
32
+ - A Pi launcher that prefers a fresh standalone `pi` install by default and only uses the bundled Feynman runtime when you explicitly allow it.
33
+ - A Pi extension with operational commands: `/plan`, `/map`, `/animate`, `/verify`, `/bench`, `/evolve`, `/prompt-evolve`, `/feedback`, `/policy`, `/outputs`, `/trace`.
34
+ - Teaching workflows as prompt templates: `/learn`, `/diagnose`, `/quiz`, `/bridge`.
35
+ - A prompt-evolution loop that scores prompt templates with natural-language feedback and picks revisions with a PROSPER-style multi-objective selector.
36
+ - 12 domains: math, science, philosophy, code, law, politics, psychology, medicine, arts, history, and general.
37
+ - Deterministic artifacts under `.keating/`:
38
+ - lesson plans with domain-specific guidance (code gets live-code phases, law gets case citations, etc.)
39
+ - richer Mermaid meaning maps rendered through `oxdraw`
40
+ - self-contained `manim-web` animation bundles: function-graphs, distribution-bars, belief-updates, code-traces, timelines, case-diagrams, mind-maps, and concept-cards
41
+ - fact-checking verification checklists that must be completed before teaching
42
+ - benchmark reports
43
+ - evolution reports
44
+ - prompt-evolution reports and evolved prompt snapshots
45
+ - the current policy and policy archive
46
+ - persistent learner state and feedback signals
47
+ - Persisted traces that explain why benchmark runs and evolution candidates succeeded or failed.
48
+ - A test suite with property checks, fuzz-style inputs, and an end-to-end acceptance pipeline.
49
+
50
+ ## Quick Start
51
+
52
+ ### From the Web
53
+
54
+ Visit **[keating.help](https://keating.help)** to use Keating directly in your browser with:
55
+ - Your own API keys (stored locally)
56
+ - Local model inference via WebGPU (Gemma 4 E4B)
57
+ - Full hyperteacher experience without installation
58
+
59
+ ### From the Command Line
60
+
61
+ Install via curl:
62
+
63
+ ```bash
64
+ curl -fsSL https://github.com/Diogenesoftoronto/keating/releases/latest/download/install.sh | bash
65
+ ```
66
+
67
+ Or with npm/pnpm/bun:
68
+
69
+ ```bash
70
+ npm install -g @interleavelove/keating
71
+ pnpm add -g @interleavelove/keating
72
+ bun add -g @interleavelove/keating
73
+ ```
74
+
75
+ ### Development
76
+
77
+ <video src="docs/assets/doctor.mp4" autoplay loop muted width="100%"></video>
78
+
79
+ ```bash
80
+ mise run build
81
+ mise run doctor
82
+ mise run docs:diagrams
83
+ mise run bench
84
+ mise run evolve
85
+ mise run prompt-evolve -- learn
86
+ mise run map -- derivative
87
+ mise run animate -- derivative
88
+ mise run trace
89
+ mise run shell
90
+ ```
91
+
92
+ Keating reads runtime/model defaults from `keating.config.json`.
93
+
94
+ ```json
95
+ {
96
+ "pi": {
97
+ "runtimePreference": "standalone-only",
98
+ "defaultProvider": "google",
99
+ "defaultModel": "google/gemini-2.5-pro",
100
+ "defaultThinking": "medium"
101
+ },
102
+ "debug": {
103
+ "persistTraces": true,
104
+ "traceTopLearners": 3,
105
+ "consoleSummary": true
106
+ }
107
+ }
108
+ ```
109
+
110
+ `runtimePreference` supports:
111
+
112
+ - `standalone-only`
113
+ - `prefer-standalone`
114
+ - `embedded-only`
115
+
116
+ Inside the Pi shell:
117
+
118
+ ```text
119
+ /plan derivative
120
+ /map derivative
121
+ /animate derivative
122
+ /verify derivative
123
+ /learn derivative
124
+ /quiz derivative
125
+ /bench derivative
126
+ /evolve derivative
127
+ /prompt-evolve learn
128
+ /feedback up derivative
129
+ /trace derivative
130
+ /outputs
131
+ ```
132
+
133
+ ## Prompt Evolution
134
+
135
+ `prompt-evolve` does not silently rewrite the checked-in prompt template. It reads a source prompt such as `pi/prompts/learn.md`, scores it on teaching objectives like learner voice, diagnosis, verification, retrieval, transfer, and structure, then writes:
136
+
137
+ - `.keating/outputs/prompt-evolution/learn.md`
138
+ - `.keating/outputs/prompt-evolution/learn.evolved.md`
139
+
140
+ Example:
141
+
142
+ Before:
143
+
144
+ ```md
145
+ Teach the learner the following topic: $@
146
+
147
+ Workflow:
148
+ 1. Start with a short diagnostic question.
149
+ 2. Explain the concept.
150
+ 3. End with a summary.
151
+ ```
152
+
153
+ After `mise run prompt-evolve -- learn`:
154
+
155
+ ```md
156
+ Teach the learner the following topic: $@
157
+
158
+ Workflow:
159
+ 1. Start with a short diagnostic question.
160
+ 1a. Separate missing prerequisite, partial intuition, and formal gap before choosing the next move.
161
+ 2. Explain the concept.
162
+ 5a. Make the learner reconstruct the core idea from memory rather than merely agreeing with your explanation.
163
+ 6a. Ask the learner to carry the idea into a new setting so they prove they can transfer it.
164
+ 0c. Keep Keating's standard in view: "Boys, you must strive to find your own voice..."
165
+ ```
166
+
167
+ The point is not cosmetic prompt churn or benchmark gaming. The loop tries to produce prompts that improve human learning outcomes: sharper diagnosis, stronger reconstruction from memory, better transfer, and clearer learner articulation.
168
+
169
+ ## Benchmarking Cognitive Friction
170
+
171
+ To ensure that Keating serves as a bridge to independent understanding rather than a shortcut to agreement, we maintain a **Synthetic Learner Suite**.
172
+
173
+ Recent results using small models (1–2B parameters) show that the system successfully identifies and redirects "Surface Agreement." Key findings include:
174
+ - **Redirection Effectiveness:** Identifying meta-responses ("That's a great question!") and insisting on personal application before advancing.
175
+ - **Intuition-First Efficacy:** Measurable self-correction in technical domains (e.g., correcting conflations between function values and derivatives).
176
+ - **Voice Persistence:** Penalizing rote echoing of the teacher and rewarding novel analogies or domain transfers.
177
+
178
+ Detailed results are available in our latest study: `docs/study.typ`.
179
+
180
+ ## Project Layout
181
+
182
+ - `src/core/`: lesson planning, benchmarks, policy mutation, artifact helpers.
183
+ - `src/core/animation.ts`: `manim-web` bundle generation for visual teaching artifacts.
184
+ - `src/runtime/`: Pi/Feynman runtime detection and shell launcher.
185
+ - `src/pi/`: the compiled Pi extension entrypoint.
186
+ - `pi/prompts/`: teaching prompt templates.
187
+ - `pi/skills/`: teaching skills for the runtime.
188
+ - `docs/`: architecture, testing strategy, and diagrams.
189
+
190
+ Key docs:
191
+
192
+ - `docs/ARCHITECTURE.md`
193
+ - `docs/OXDRAW-TUTORIAL.md`
194
+ - `docs/VISUAL-ARCHITECTURE.md`
195
+
196
+ ## Design Notes
197
+
198
+ The system deliberately separates:
199
+
200
+ - live teaching behavior, which stays in Pi prompts and skills,
201
+ - deterministic pedagogy artifacts, which are generated by local code and kept inspectable,
202
+ - self-improvement, which runs against a synthetic learner suite before policy changes are accepted.
203
+
204
+ That split keeps the interactive shell flexible while making the improvement loop testable without an LLM in the loop.
205
+
206
+ ## Testing
207
+
208
+ <video src="docs/assets/tests.mp4" autoplay loop muted width="100%"></video>
209
+
210
+ ```bash
211
+ mise run test
212
+ ```
213
+
214
+ The test suite covers:
215
+ - property checks for lesson plans and maps
216
+ - fuzzed teaching policies and topics
217
+ - visual grammar invariants for animations
218
+ - end-to-end artifact generation and trace persistence
219
+
220
+ ## Visual Teaching Layer
221
+
222
+ Keating now treats diagrams and animations as first-class teaching artifacts instead of optional garnish.
223
+
224
+ - `mise run map -- <topic>` writes a meaning map with teaching loop, concept structure, misconceptions, practice, and transfer hooks, then renders it with `oxdraw` when available.
225
+ - `mise run animate -- <topic>` writes a browser-runnable `manim-web` bundle under `.keating/outputs/animations/<topic>/`.
226
+ - Each animation bundle includes:
227
+ - `player.html`
228
+ - `scene.mjs`
229
+ - `storyboard.md`
230
+ - `manifest.json`
231
+ - The animation manifest explains why a particular scene grammar was selected, so the visual layer is inspectable alongside benchmark and evolution traces.
232
+
233
+ ## Debugging Self-Evolution
234
+
235
+ Keating persists detailed trace artifacts under `.keating/outputs/traces/`.
236
+
237
+ - Benchmark traces show:
238
+ - per-topic metric means
239
+ - the strongest and weakest synthetic learners
240
+ - natural-language reasons for strong or weak outcomes
241
+ - Evolution traces show:
242
+ - every explored candidate
243
+ - score and weakest-topic deltas
244
+ - novelty scores
245
+ - gate outcomes
246
+ - acceptance or rejection reasons
247
+ - parameter deltas from the parent policy
248
+ - Prompt-evolution artifacts show:
249
+ - baseline feedback on the source prompt
250
+ - candidate objective vectors
251
+ - the PROSPER-style preference score
252
+ - the recommended evolved prompt snapshot
253
+
254
+ Useful commands:
255
+
256
+ ```bash
257
+ mise run doctor
258
+ mise run bench -- derivative
259
+ mise run evolve -- derivative
260
+ mise run prompt-evolve -- learn
261
+ mise run trace -- derivative
262
+ ```
263
+
264
+ ## Documentation
265
+
266
+ - Architecture overview: `docs/ARCHITECTURE.md`
267
+ - Visual system architecture: `docs/VISUAL-ARCHITECTURE.md`
268
+ - `oxdraw` authoring and rendering tutorial: `docs/OXDRAW-TUTORIAL.md`
269
+
270
+ Regenerate the checked-in docs SVGs with:
271
+
272
+ ```bash
273
+ mise run docs:diagrams
274
+ ```
package/bin/keating.js ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ const MIN_NODE_VERSION = "20.19.0";
3
+
4
+ function parseNodeVersion(version) {
5
+ const [major = "0", minor = "0", patch = "0"] = version.replace(/^v/, "").split(".");
6
+ return {
7
+ major: Number.parseInt(major, 10) || 0,
8
+ minor: Number.parseInt(minor, 10) || 0,
9
+ patch: Number.parseInt(patch, 10) || 0,
10
+ };
11
+ }
12
+
13
+ function compareNodeVersions(left, right) {
14
+ if (left.major !== right.major) return left.major - right.major;
15
+ if (left.minor !== right.minor) return left.minor - right.minor;
16
+ return left.patch - right.patch;
17
+ }
18
+
19
+ if (compareNodeVersions(parseNodeVersion(process.versions.node), parseNodeVersion(MIN_NODE_VERSION)) < 0) {
20
+ const isWindows = process.platform === "win32";
21
+ console.error(`keating requires Node.js ${MIN_NODE_VERSION} or later (detected ${process.versions.node}).`);
22
+ console.error(isWindows
23
+ ? "Install a newer Node.js from https://nodejs.org, or use the standalone installer:"
24
+ : "Switch to Node 20 with `nvm install 20 && nvm use 20`, or use the standalone installer:");
25
+ console.error(isWindows
26
+ ? "irm https://keating.help/install.ps1 | iex"
27
+ : "curl -fsSL https://keating.help/install | bash");
28
+ process.exit(1);
29
+ }
30
+
31
+ await import(new URL("../dist/src/cli/main.js", import.meta.url).href);
@@ -0,0 +1,165 @@
1
+ import { access } from "node:fs/promises";
2
+ import { relative } from "node:path";
3
+ import { join } from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+ import { configPath, loadKeatingConfig } from "../core/config.js";
6
+ import { animateTopicArtifact, benchPolicyArtifact, currentPolicySummary, ensureProjectScaffold, evolvePolicyArtifact, evolvePromptArtifact, improveArtifact, improveHistory, listArtifacts, mapTopicArtifact, planTopicArtifact, verifyTopicArtifact } from "../core/project.js";
7
+ import { detectPiRuntime, launchPi } from "../runtime/pi.js";
8
+ function printUsage() {
9
+ console.log(`keating commands:
10
+ shell [initial prompt...] Launch the Pi-powered hyperteacher shell
11
+ plan <topic> Write a deterministic lesson plan artifact
12
+ map <topic> Write a Mermaid map and render with oxdraw if present
13
+ animate <topic> Write a manim-web animation bundle for a topic
14
+ verify <topic> Generate a fact-checking checklist for a topic
15
+ improve Generate a self-improvement proposal for the teaching code
16
+ improve history Show the improvement attempt history
17
+ bench [topic] Run the learner benchmark suite
18
+ evolve [topic] Evolve the current teaching policy
19
+ prompt-evolve [prompt] Evolve a prompt template with prompt-learning feedback
20
+ policy Print the active policy
21
+ trace [substring] List persisted debug traces and artifacts
22
+ doctor Inspect Pi/Feynman and oxdraw availability
23
+ `);
24
+ }
25
+ async function run() {
26
+ const [command = "shell", ...args] = process.argv.slice(2);
27
+ const cwd = process.cwd();
28
+ switch (command) {
29
+ case "shell": {
30
+ const exitCode = await launchPi(cwd, args);
31
+ process.exitCode = exitCode;
32
+ return;
33
+ }
34
+ case "plan": {
35
+ const topic = args.join(" ").trim();
36
+ if (!topic)
37
+ throw new Error("plan requires a topic.");
38
+ const artifact = await planTopicArtifact(cwd, topic);
39
+ console.log(relative(cwd, artifact.planPath));
40
+ return;
41
+ }
42
+ case "map": {
43
+ const topic = args.join(" ").trim();
44
+ if (!topic)
45
+ throw new Error("map requires a topic.");
46
+ const artifact = await mapTopicArtifact(cwd, topic);
47
+ console.log(relative(cwd, artifact.mmdPath));
48
+ if (artifact.svgPath)
49
+ console.log(relative(cwd, artifact.svgPath));
50
+ return;
51
+ }
52
+ case "animate": {
53
+ const topic = args.join(" ").trim();
54
+ if (!topic)
55
+ throw new Error("animate requires a topic.");
56
+ const artifact = await animateTopicArtifact(cwd, topic);
57
+ console.log(relative(cwd, artifact.playerPath));
58
+ console.log(relative(cwd, artifact.scenePath));
59
+ console.log(relative(cwd, artifact.storyboardPath));
60
+ console.log(relative(cwd, artifact.manifestPath));
61
+ return;
62
+ }
63
+ case "verify": {
64
+ const topic = args.join(" ").trim();
65
+ if (!topic)
66
+ throw new Error("verify requires a topic.");
67
+ const result = await verifyTopicArtifact(cwd, topic);
68
+ if (result.alreadyVerified) {
69
+ console.log(`Already verified: ${relative(cwd, result.checklistPath)}`);
70
+ }
71
+ else {
72
+ console.log(`Verification checklist: ${relative(cwd, result.checklistPath)}`);
73
+ }
74
+ return;
75
+ }
76
+ case "bench": {
77
+ const topic = args.join(" ").trim() || undefined;
78
+ const result = await benchPolicyArtifact(cwd, topic);
79
+ console.log(`${result.overallScore.toFixed(2)} ${relative(cwd, result.reportPath)}`);
80
+ if (result.tracePath)
81
+ console.log(relative(cwd, result.tracePath));
82
+ return;
83
+ }
84
+ case "evolve": {
85
+ const topic = args.join(" ").trim() || undefined;
86
+ const result = await evolvePolicyArtifact(cwd, topic);
87
+ console.log(`${result.bestScore.toFixed(2)} ${relative(cwd, result.reportPath)}`);
88
+ if (result.tracePath)
89
+ console.log(relative(cwd, result.tracePath));
90
+ return;
91
+ }
92
+ case "prompt-evolve": {
93
+ const promptName = args.join(" ").trim() || "learn";
94
+ const result = await evolvePromptArtifact(cwd, promptName);
95
+ console.log(`${result.bestScore.toFixed(2)} ${relative(cwd, result.reportPath)}`);
96
+ console.log(relative(cwd, result.evolvedPromptPath));
97
+ return;
98
+ }
99
+ case "improve": {
100
+ if (args[0] === "history") {
101
+ const md = await improveHistory(cwd);
102
+ console.log(md);
103
+ return;
104
+ }
105
+ const artifact = await improveArtifact(cwd);
106
+ console.log(`Proposal: ${artifact.proposal.id}`);
107
+ console.log(`Targets: ${artifact.proposal.targets.map(t => t.file).join(", ")}`);
108
+ console.log(relative(cwd, artifact.proposalPath));
109
+ return;
110
+ }
111
+ case "policy": {
112
+ await ensureProjectScaffold(cwd);
113
+ console.log(await currentPolicySummary(cwd));
114
+ return;
115
+ }
116
+ case "trace": {
117
+ await ensureProjectScaffold(cwd);
118
+ const query = args.join(" ").trim().toLowerCase();
119
+ const artifacts = await listArtifacts(cwd);
120
+ for (const artifact of artifacts) {
121
+ if (!query || artifact.path.toLowerCase().includes(query) || artifact.label.toLowerCase().includes(query)) {
122
+ console.log(artifact.path);
123
+ }
124
+ }
125
+ return;
126
+ }
127
+ case "doctor": {
128
+ await ensureProjectScaffold(cwd);
129
+ const config = await loadKeatingConfig(cwd);
130
+ const runtime = await detectPiRuntime(cwd);
131
+ const oxdraw = spawnSync("which", ["oxdraw"], { encoding: "utf8" });
132
+ const manimWebPath = join(cwd, "node_modules", "manim-web", "dist", "index.js");
133
+ const manimWebInstalled = await access(manimWebPath).then(() => true, () => false);
134
+ console.log(`config_path=${configPath(cwd)}`);
135
+ console.log(`pi_runtime_preference=${config.pi.runtimePreference}`);
136
+ console.log(`pi_default_provider=${config.pi.defaultProvider ?? "unset"}`);
137
+ console.log(`pi_default_model=${config.pi.defaultModel ?? "unset"}`);
138
+ console.log(`pi_default_thinking=${config.pi.defaultThinking ?? "unset"}`);
139
+ console.log(`debug_persist_traces=${String(config.debug.persistTraces)}`);
140
+ console.log(`debug_trace_top_learners=${String(config.debug.traceTopLearners)}`);
141
+ console.log(`debug_console_summary=${String(config.debug.consoleSummary)}`);
142
+ console.log(`pi_runtime=${runtime.selected ? runtime.selected.kind : "missing"}`);
143
+ console.log(`pi_standalone=${runtime.standalone ? runtime.standalone.command : "missing"}`);
144
+ console.log(`pi_embedded=${runtime.embedded ? runtime.embedded.cliPath ?? runtime.embedded.command : "missing"}`);
145
+ if (runtime.selected)
146
+ console.log(`pi_command=${runtime.selected.command}`);
147
+ console.log(`oxdraw=${oxdraw.status === 0 ? oxdraw.stdout.trim() : "missing"}`);
148
+ console.log(`manim_web=${manimWebInstalled ? manimWebPath : "missing"}`);
149
+ return;
150
+ }
151
+ case "help":
152
+ case "--help":
153
+ case "-h": {
154
+ printUsage();
155
+ return;
156
+ }
157
+ default: {
158
+ throw new Error(`Unknown command: ${command}`);
159
+ }
160
+ }
161
+ }
162
+ run().catch((error) => {
163
+ console.error(error instanceof Error ? error.message : String(error));
164
+ process.exitCode = 1;
165
+ });