@mindrian_os/install 1.13.0-beta.12 → 1.13.0-beta.14

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 (123) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +57 -10
  3. package/README.md +74 -572
  4. package/commands/act.md +1 -0
  5. package/commands/admin.md +1 -0
  6. package/commands/analyze-needs.md +1 -0
  7. package/commands/analyze-systems.md +1 -0
  8. package/commands/analyze-timing.md +1 -0
  9. package/commands/auto-explore.md +2 -0
  10. package/commands/beautiful-question.md +1 -0
  11. package/commands/brain-derive.md +1 -0
  12. package/commands/build-knowledge.md +1 -0
  13. package/commands/build-thesis.md +1 -0
  14. package/commands/causal.md +1 -0
  15. package/commands/challenge-assumptions.md +1 -0
  16. package/commands/compare-ventures.md +1 -0
  17. package/commands/dashboard.md +1 -0
  18. package/commands/deep-grade.md +1 -0
  19. package/commands/diagnose.md +1 -0
  20. package/commands/diagnostics.md +1 -0
  21. package/commands/doctor.md +2 -1
  22. package/commands/dominant-designs.md +1 -0
  23. package/commands/explain-decision.md +1 -0
  24. package/commands/explore-domains.md +1 -0
  25. package/commands/explore-futures.md +1 -0
  26. package/commands/explore-trends.md +1 -0
  27. package/commands/export.md +1 -0
  28. package/commands/feynman-timeline-refresh.md +78 -0
  29. package/commands/file-meeting.md +1 -0
  30. package/commands/find-analogies.md +1 -0
  31. package/commands/find-bottlenecks.md +1 -0
  32. package/commands/find-connections.md +1 -0
  33. package/commands/funding.md +1 -0
  34. package/commands/grade.md +1 -0
  35. package/commands/graph.md +1 -0
  36. package/commands/hat-briefing.md +1 -0
  37. package/commands/heal.md +1 -0
  38. package/commands/help.md +1 -0
  39. package/commands/hmi-status.md +1 -0
  40. package/commands/jtbd.md +1 -0
  41. package/commands/leadership.md +1 -0
  42. package/commands/lean-canvas.md +1 -0
  43. package/commands/macro-trends.md +1 -0
  44. package/commands/map-unknowns.md +1 -0
  45. package/commands/memory.md +1 -0
  46. package/commands/models.md +1 -0
  47. package/commands/mos-reason.md +1 -0
  48. package/commands/mullins.md +1 -0
  49. package/commands/new-project.md +1 -0
  50. package/commands/onboard.md +1 -0
  51. package/commands/operator.md +2 -1
  52. package/commands/opportunities.md +1 -0
  53. package/commands/organize.md +1 -0
  54. package/commands/persona.md +1 -0
  55. package/commands/pipeline.md +1 -0
  56. package/commands/present.md +1 -0
  57. package/commands/publish.md +1 -0
  58. package/commands/query.md +1 -0
  59. package/commands/radar.md +1 -0
  60. package/commands/reanalyze.md +1 -0
  61. package/commands/research.md +1 -0
  62. package/commands/room.md +1 -0
  63. package/commands/rooms.md +1 -0
  64. package/commands/root-cause.md +1 -0
  65. package/commands/rs-experts.md +1 -0
  66. package/commands/rs-explain.md +1 -0
  67. package/commands/rs-fetch.md +1 -0
  68. package/commands/rs-thesis.md +1 -0
  69. package/commands/scenario-plan.md +1 -0
  70. package/commands/scheduled-tasks.md +1 -0
  71. package/commands/score-innovation.md +1 -0
  72. package/commands/scout.md +1 -0
  73. package/commands/setup.md +8 -3
  74. package/commands/snapshot.md +1 -0
  75. package/commands/speakers.md +1 -0
  76. package/commands/splash.md +1 -0
  77. package/commands/status.md +1 -0
  78. package/commands/structure-argument.md +1 -0
  79. package/commands/suggest-next.md +1 -0
  80. package/commands/systems-thinking.md +1 -0
  81. package/commands/think-hats.md +1 -0
  82. package/commands/update.md +1 -0
  83. package/commands/user-needs.md +1 -0
  84. package/commands/validate.md +1 -0
  85. package/commands/value-proposition.md +1 -0
  86. package/commands/vault.md +1 -0
  87. package/commands/visualize.md +1 -0
  88. package/commands/whitespace.md +1 -0
  89. package/commands/wiki.md +1 -0
  90. package/lib/brain/framework-chain-slice.cjs +193 -0
  91. package/lib/core/active-plugin-root.cjs +71 -6
  92. package/lib/core/brain-client.cjs +451 -36
  93. package/lib/core/cache-prune.cjs +208 -0
  94. package/lib/core/feynman/ROOM.md +25 -0
  95. package/lib/core/feynman/timeline-renderer.cjs +197 -0
  96. package/lib/core/feynman/timeline-runner.cjs +281 -0
  97. package/lib/core/navigation/edges.cjs +86 -0
  98. package/lib/core/navigation/insights.cjs +37 -0
  99. package/lib/core/navigation/memory-events.cjs +56 -1
  100. package/lib/core/navigation/neighborhood.cjs +5 -4
  101. package/lib/core/navigation/packet.cjs +176 -10
  102. package/lib/core/navigation/projections.cjs +201 -0
  103. package/lib/core/navigation.cjs +31 -0
  104. package/lib/core/resolve-brain-key.cjs +201 -0
  105. package/lib/mcp/larry-server-instructions.md +1 -1
  106. package/lib/memory/brain-cypher-chain-slice.test.cjs +368 -0
  107. package/lib/memory/f-selector-ranker.test.cjs +593 -0
  108. package/lib/memory/navigation-projections.test.cjs +241 -0
  109. package/lib/memory/navigation-write-edge.test.cjs +206 -0
  110. package/lib/memory/packet-chain-hint.test.cjs +407 -0
  111. package/lib/memory/packet-schema-validation.test.cjs +317 -0
  112. package/lib/memory/per-command-jtbd-derivation.test.cjs +130 -0
  113. package/lib/memory/per-command-teaching.test.cjs +110 -0
  114. package/lib/memory/run-feynman-tests.cjs +121 -0
  115. package/lib/memory/security-trifecta.test.cjs +23 -6
  116. package/lib/memory/selector-decisions.test.cjs +417 -0
  117. package/lib/memory/selector-miss.test.cjs +290 -0
  118. package/lib/workflow/f-selector-ranker.cjs +420 -0
  119. package/lib/workflow/selector-decisions.cjs +368 -0
  120. package/package.json +4 -1
  121. package/references/design/email-template-standard.md +1 -1
  122. package/references/user-research/2026-04-05-leah-lawrence-session.md +3 -3
  123. package/skills/brain-connector/SKILL.md +9 -3
@@ -0,0 +1,368 @@
1
+ 'use strict';
2
+ /*
3
+ * Copyright (c) 2026 Mindrian. BSL 1.1.
4
+ *
5
+ * Phase 125-06 -- F-selector decision recording + decay weight (D7 implementation).
6
+ * =================================================================================
7
+ * Implements CONTEXT.md D7: when the user picks F.1 (defer) or F.2 (reject) on a
8
+ * ranked command, emit THREE side-effects atomically:
9
+ *
10
+ * 1. memory_event row (event_type='f_selector_decision') via
11
+ * navigation.logMemoryEvent
12
+ * 2. typed cascade edge (DEFERRED | REJECTED) via navigation.writeEdge
13
+ * (Plan 00 primitive)
14
+ * 3. decay-weight applied to next N rankings (via applyDecayWeight reader,
15
+ * consumed by Plan 05 ranker's opts._applyDecayWeight IoC hook)
16
+ *
17
+ * All writes route through the navigation.cjs chokepoint. ZERO direct room-db
18
+ * access. ZERO direct loads of internal navigation submodules (the chokepoint
19
+ * is the only door). The grep audit in lib/memory/selector-decisions.test.cjs
20
+ * Test 7 enforces these invariants structurally on every CI run.
21
+ *
22
+ * Canon binding:
23
+ * Part 4: every choice is graph data; defer/reject become typed edges.
24
+ * Part 7: reuse before build; we ship as thin glue over Plan 00's
25
+ * writeEdge + Phase 109's logMemoryEvent + Phase 109's
26
+ * findRecentChanges -- not a single net-new SQL statement.
27
+ * Part 8: LOCAL only; no Brain calls; no user content leaves the room.
28
+ * Part 9: SQL remembers and navigates; this module reads-and-writes
29
+ * through the navigation chokepoint, never around it.
30
+ *
31
+ * Function signatures LOCKED in 125-CONTEXT.md "Function signatures":
32
+ * recordSelectorDecision({decision, command, framework, reason?, roomState})
33
+ * -> {decision_id, edge_id} on success | {ok: false, reason, detail?} on failure
34
+ * applyDecayWeight(base_score, command_id, roomState) -> number
35
+ *
36
+ * D7 exponential decay formula (CONTEXT.md verbatim):
37
+ * adjusted_score = base_score * (1 - exp(-(invocations_since_decision / N)))
38
+ * where N = 5 (DECAY_WINDOW).
39
+ *
40
+ * At decision time (n=0): factor = 0 (command pushed to bottom).
41
+ * 5 invocations later: factor ~ 0.6321.
42
+ * 10 invocations later: factor ~ 0.8647.
43
+ * 15+ invocations later: factor approaches 1 (decision effectively expires).
44
+ *
45
+ * License: BSL 1.1.
46
+ */
47
+
48
+ const navigation = require('../core/navigation.cjs');
49
+
50
+ // CONTEXT.md Open Question #6 lean: decay window N=5 invocations. Tunable per-
51
+ // room via .mos/config.json in v2; fixed at 5 for v1. Exposed as a module
52
+ // constant so consumers (Plan 05 ranker, debug tooling, future tuning passes)
53
+ // can reference DECAY_WINDOW symbolically rather than hard-coding 5.
54
+ const DECAY_WINDOW = 5;
55
+
56
+ // CONTEXT.md RESEARCH G-09 lean: exclude commands whose decay factor is below
57
+ // this threshold from the top-K list entirely (freshly-rejected commands
58
+ // shouldn't appear in the very next selector). Plan 05 ranker may wire this
59
+ // helper via opts to filter. Threshold 0.1 means "first invocation after a
60
+ // decision suppresses the command; from invocation 1 onwards the command
61
+ // resurfaces with the decayed weight". Configurable in v2.
62
+ const EXCLUSION_THRESHOLD = 0.1;
63
+
64
+ // CONTEXT.md Open Question #7 lean: clock-driven expiry alongside the
65
+ // invocation-count decay. DEFERRED edges carry expires_at 30 days from
66
+ // decision time; REJECTED edges have no expiry. This handles long-idle rooms
67
+ // gracefully (a deferred command shouldn't stay suppressed for a year if the
68
+ // user simply walked away from the room for weeks).
69
+ const DEFAULT_DEFER_EXPIRY_DAYS = 30;
70
+
71
+ function _defaultExpiresAt() {
72
+ return new Date(Date.now() + DEFAULT_DEFER_EXPIRY_DAYS * 24 * 3600 * 1000).toISOString();
73
+ }
74
+
75
+ // ---------------------------------------------------------------------------
76
+ // recordSelectorDecision -- the D7 writer.
77
+ //
78
+ // CONTEXT.md locked signature:
79
+ // recordSelectorDecision({decision, command, framework, reason?, roomState})
80
+ // -> {decision_id, edge_id}
81
+ //
82
+ // db handle is read from roomState.db per the design lock (callers populate
83
+ // roomState.db before invocation). This keeps the signature stable as the
84
+ // roomState shape evolves and prevents accidental signature drift.
85
+ //
86
+ // Returns {ok: true, decision_id, edge_id} on success, or
87
+ // {ok: false, reason, detail?} on validation/write failure. Defensive --
88
+ // never throws on caller input.
89
+ // ---------------------------------------------------------------------------
90
+ function recordSelectorDecision(args) {
91
+ const o = args || {};
92
+ const decision = o.decision;
93
+ const command = o.command;
94
+ const framework = o.framework;
95
+ // Reason is optional. CONTEXT.md acceptance: "Reason is optional -- when
96
+ // omitted, payload.reason is null AND edge.properties.reason is null."
97
+ const reason = (typeof o.reason === 'string' && o.reason.length > 0) ? o.reason : null;
98
+ const roomState = o.roomState || {};
99
+ const db = roomState.db;
100
+ const score_at_decision = (typeof o.score_at_decision === 'number') ? o.score_at_decision : null;
101
+
102
+ // Validation gate (defensive; never throws).
103
+ if (decision !== 'defer' && decision !== 'reject') {
104
+ return { ok: false, reason: 'invalid_decision' };
105
+ }
106
+ if (typeof command !== 'string' || command.length === 0) {
107
+ return { ok: false, reason: 'invalid_command' };
108
+ }
109
+ if (typeof framework !== 'string' || framework.length === 0) {
110
+ return { ok: false, reason: 'invalid_framework' };
111
+ }
112
+ if (!db) {
113
+ // Locked design: db must be on roomState.db. Callers populate this.
114
+ return { ok: false, reason: 'invalid_db' };
115
+ }
116
+
117
+ const investment_level_at_decision =
118
+ (typeof roomState.investment_level === 'number') ? roomState.investment_level : 0;
119
+ const edgeSemantic = (decision === 'defer') ? 'DEFERRED' : 'REJECTED';
120
+ const expiresAt = (decision === 'defer') ? _defaultExpiresAt() : null;
121
+
122
+ // ---------------------------------------------------------------------
123
+ // Step 1: write memory_event via the navigation chokepoint.
124
+ // CONTEXT.md memory_event payload schema (verbatim):
125
+ // {
126
+ // event_type: 'f_selector_decision', // overridden by logMemoryEvent
127
+ // decision: 'defer' | 'reject',
128
+ // command, framework,
129
+ // reason: string | null,
130
+ // edge_semantic: 'DEFERRED' | 'REJECTED',
131
+ // expires_at: ISO string | null,
132
+ // score_at_decision: number | null,
133
+ // investment_level_at_decision: number,
134
+ // source_path: 'f-selector:' + command,
135
+ // created_by: 'user',
136
+ // }
137
+ // ---------------------------------------------------------------------
138
+ const memEvent = navigation.logMemoryEvent(db, 'f_selector_decision', {
139
+ decision,
140
+ command,
141
+ framework,
142
+ reason,
143
+ edge_semantic: edgeSemantic,
144
+ expires_at: expiresAt,
145
+ score_at_decision,
146
+ investment_level_at_decision,
147
+ source_path: 'f-selector:' + command,
148
+ created_by: 'user',
149
+ });
150
+ if (!memEvent || !memEvent.ok) {
151
+ return {
152
+ ok: false,
153
+ reason: 'memory_event_failed',
154
+ detail: memEvent ? memEvent.reason : 'unknown',
155
+ };
156
+ }
157
+ const decision_id = memEvent.eventId;
158
+
159
+ // ---------------------------------------------------------------------
160
+ // Step 2: write typed cascade edge via Plan 00's writeEdge primitive.
161
+ // CONTEXT.md edge schemas:
162
+ // DEFERRED: {reason, decision_id, expires_at}
163
+ // REJECTED: {reason, decision_id} (no expires_at)
164
+ // ---------------------------------------------------------------------
165
+ const edgeProps = (decision === 'defer')
166
+ ? { reason, decision_id, expires_at: expiresAt }
167
+ : { reason, decision_id };
168
+
169
+ const edgeResult = navigation.writeEdge(db, {
170
+ source_id: 'cmd:' + command,
171
+ target_id: 'framework:' + framework,
172
+ edge_type: edgeSemantic,
173
+ properties: edgeProps,
174
+ });
175
+
176
+ if (!edgeResult || !edgeResult.ok) {
177
+ return {
178
+ ok: false,
179
+ reason: 'edge_write_failed',
180
+ detail: edgeResult ? edgeResult.reason : 'unknown',
181
+ };
182
+ }
183
+
184
+ return {
185
+ ok: true,
186
+ decision_id,
187
+ edge_id: edgeResult.edge_id,
188
+ };
189
+ }
190
+
191
+ // ---------------------------------------------------------------------------
192
+ // _invocationsSinceDecision -- internal counter helper.
193
+ //
194
+ // Counts framework_invoked memory_event rows newer than the most recent
195
+ // f_selector_decision for this command. When roomState provides a pre-
196
+ // computed counter (test injection or upstream cache), prefer that --
197
+ // keeps applyDecayWeight pure for unit tests AND db-backed for production.
198
+ //
199
+ // Returns:
200
+ // number (>= 0) when a decision is on record.
201
+ // Infinity when no decision is on record (no decay applies).
202
+ // ---------------------------------------------------------------------------
203
+ function _invocationsSinceDecision(db, command, roomState) {
204
+ // Test seam: explicit pre-computed counter wins.
205
+ if (roomState
206
+ && roomState.invocationsSinceDecision
207
+ && typeof roomState.invocationsSinceDecision[command] === 'number') {
208
+ return roomState.invocationsSinceDecision[command];
209
+ }
210
+ if (!db) {
211
+ // No db and no counter -> treat as no decision (return Infinity sentinel).
212
+ return Infinity;
213
+ }
214
+ // Find the most recent f_selector_decision for this command.
215
+ // findRecentChanges returns rows ordered by created_at DESC; we scan up to
216
+ // 100 rows (the decision frequency is human-paced -- 100 is generous).
217
+ const recent = navigation.findRecentChanges(db, 0, {
218
+ eventType: 'f_selector_decision',
219
+ limit: 100,
220
+ });
221
+ let lastDecisionAt = null;
222
+ for (const row of recent) {
223
+ if (row && row.properties && row.properties.command === command) {
224
+ if (lastDecisionAt === null || row.createdAt > lastDecisionAt) {
225
+ lastDecisionAt = row.createdAt;
226
+ }
227
+ }
228
+ }
229
+ if (lastDecisionAt === null) return Infinity; // no decision -> no decay
230
+ // Count framework_invoked events strictly newer than lastDecisionAt.
231
+ // findRecentChanges uses strict '>' on created_at per Phase 109.
232
+ const invocations = navigation.findRecentChanges(db, lastDecisionAt, {
233
+ eventType: 'framework_invoked',
234
+ limit: 1000,
235
+ });
236
+ return invocations.length;
237
+ }
238
+
239
+ // ---------------------------------------------------------------------------
240
+ // applyDecayWeight -- D7 exponential decay reader.
241
+ //
242
+ // CONTEXT.md locked signature:
243
+ // applyDecayWeight(base_score: number, command_id: string, roomState) -> number
244
+ //
245
+ // Pure when roomState supplies invocationsSinceDecision[command_id].
246
+ // Reads via navigation.findRecentChanges when db is on roomState.db.
247
+ //
248
+ // Decay formula:
249
+ // factor = 1 - exp(-(n / DECAY_WINDOW))
250
+ // adjusted = base_score * factor
251
+ //
252
+ // Edge cases:
253
+ // - No decision recorded -> returns base_score unchanged.
254
+ // - Non-finite or non-number base_score -> returns 0 (defensive).
255
+ // - Null/undefined roomState -> returns base_score (no history = no decay).
256
+ // ---------------------------------------------------------------------------
257
+ function applyDecayWeight(base_score, command_id, roomState) {
258
+ if (typeof base_score !== 'number' || !isFinite(base_score)) return 0;
259
+ if (typeof command_id !== 'string' || command_id.length === 0) return base_score;
260
+ const rs = (roomState && typeof roomState === 'object') ? roomState : {};
261
+ const db = rs.db ? rs.db : null;
262
+ const n = _invocationsSinceDecision(db, command_id, rs);
263
+ if (n === Infinity) return base_score; // no decision recorded; no decay
264
+ const factor = 1 - Math.exp(-(n / DECAY_WINDOW));
265
+ return base_score * factor;
266
+ }
267
+
268
+ // ---------------------------------------------------------------------------
269
+ // shouldExclude -- RESEARCH G-09 helper.
270
+ //
271
+ // Plan 05 ranker may wire this to filter freshly-rejected commands from
272
+ // top-K entirely (when their decay factor is below EXCLUSION_THRESHOLD).
273
+ // Returns true when the command should be excluded; false otherwise.
274
+ // ---------------------------------------------------------------------------
275
+ function shouldExclude(command_id, roomState) {
276
+ const rs = (roomState && typeof roomState === 'object') ? roomState : {};
277
+ const db = rs.db ? rs.db : null;
278
+ const n = _invocationsSinceDecision(db, command_id, rs);
279
+ if (n === Infinity) return false;
280
+ const factor = 1 - Math.exp(-(n / DECAY_WINDOW));
281
+ return factor < EXCLUSION_THRESHOLD;
282
+ }
283
+
284
+ // ---------------------------------------------------------------------------
285
+ // Phase 125-07 -- D8 ranker-miss capture. Writes memory_event only (no edge --
286
+ // miss is temporal signal per CONTEXT.md D8 + RESEARCH G-10). Canon Part 8:
287
+ // user_intent is LOCAL-only; lives in room.db; never crosses to Brain.
288
+ // Consumer (F-selector renderer) is responsible for the follow-up /mos:do call;
289
+ // recordSelectorMiss never routes.
290
+ //
291
+ // CONTEXT.md locked signature:
292
+ // recordSelectorMiss({top_k_offered, user_intent, roomState}) -> {miss_id}
293
+ //
294
+ // db handle is read from roomState.db per the locked design; callers populate
295
+ // roomState.db before invocation (mirrors recordSelectorDecision pattern).
296
+ //
297
+ // Returns {ok: true, miss_id} on success, or {ok: false, reason, detail?} on
298
+ // validation/write failure. Defensive -- never throws on caller input.
299
+ // ---------------------------------------------------------------------------
300
+ function recordSelectorMiss(args) {
301
+ const o = args || {};
302
+ const top_k_offered = o.top_k_offered;
303
+ const user_intent = o.user_intent;
304
+ const roomState = o.roomState || {};
305
+ const db = roomState.db;
306
+
307
+ // Validation gate (defensive; never throws). db check is first because
308
+ // without it the chokepoint call would throw a more confusing error.
309
+ if (!db) {
310
+ return { ok: false, reason: 'invalid_db' };
311
+ }
312
+ if (!Array.isArray(top_k_offered)) {
313
+ return { ok: false, reason: 'invalid_top_k_offered' };
314
+ }
315
+ if (typeof user_intent !== 'string' || user_intent.length === 0) {
316
+ return { ok: false, reason: 'invalid_user_intent' };
317
+ }
318
+
319
+ // Sanitize top_k_offered: keep ONLY {command, score} fields. Defense-in-
320
+ // depth so callers passing full RankedItem objects (with teaching /
321
+ // jtbd_summary / why / source / framework / investment_level) don't
322
+ // accidentally write those extra fields into the payload. The miss capture
323
+ // is a tuning signal, not a snapshot of the full ranker output.
324
+ const cleanOffered = top_k_offered
325
+ .filter((x) => x && typeof x.command === 'string' && typeof x.score === 'number')
326
+ .map((x) => ({ command: x.command, score: x.score }));
327
+
328
+ const investment_level_at_decision =
329
+ (typeof roomState.investment_level === 'number') ? roomState.investment_level : 0;
330
+
331
+ // Write memory_event via the navigation chokepoint. NO cascade edge --
332
+ // miss is a temporal signal per D8 (and the absence of an edge is what
333
+ // makes recordSelectorMiss strictly weaker than recordSelectorDecision).
334
+ // Canon Part 8: user_intent never leaves room.db; never crosses to Brain.
335
+ const result = navigation.logMemoryEvent(db, 'f_selector_miss', {
336
+ top_k_offered: cleanOffered,
337
+ user_intent,
338
+ investment_level_at_decision,
339
+ source_path: 'f-selector:miss',
340
+ created_by: 'user',
341
+ });
342
+
343
+ if (!result || !result.ok) {
344
+ return {
345
+ ok: false,
346
+ reason: 'memory_event_failed',
347
+ detail: result ? result.reason : 'unknown',
348
+ };
349
+ }
350
+
351
+ return { ok: true, miss_id: result.eventId };
352
+ }
353
+
354
+ module.exports = {
355
+ recordSelectorDecision,
356
+ applyDecayWeight,
357
+ shouldExclude,
358
+ recordSelectorMiss,
359
+ DECAY_WINDOW,
360
+ EXCLUSION_THRESHOLD,
361
+ DEFAULT_DEFER_EXPIRY_DAYS,
362
+ // Test seam (private; consumed only by lib/memory/selector-decisions.test.cjs
363
+ // + lib/memory/selector-miss.test.cjs).
364
+ _test: {
365
+ _invocationsSinceDecision,
366
+ _defaultExpiresAt,
367
+ },
368
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindrian_os/install",
3
- "version": "1.13.0-beta.12",
3
+ "version": "1.13.0-beta.14",
4
4
  "description": "Install MindrianOS into Claude Code with one command -- `npx @mindrian_os/install`. Ships the MindrianOS plugin (Larry + PWS methodology + Data Room) plus a setup/diagnostics CLI (install/doctor/update).",
5
5
  "scripts": {
6
6
  "mcp": "node bin/mindrian-mcp-server.cjs",
@@ -37,6 +37,9 @@
37
37
  "markdown-it": "^14.1.0",
38
38
  "zod": "^3.25.76"
39
39
  },
40
+ "devDependencies": {
41
+ "semver": "^7.7.4"
42
+ },
40
43
  "engines": {
41
44
  "node": ">=22.5.0"
42
45
  },
@@ -138,7 +138,7 @@ Rotate colors: #a63d2f, #1e3a6e, #c4a43c, #2d6b4a
138
138
  <td width="16" style="background:#2d6b4a;height:3px;">&nbsp;</td>
139
139
  </tr></table>
140
140
  <p style="...font-size:11px;color:#a09a90;">Sender Name</p>
141
- <p style="...font-size:10px;color:#444;">MindrianOS -- PWS Methodology, Prof. Lawrence Aronhime, Johns Hopkins</p>
141
+ <p style="...font-size:10px;color:#444;">MindrianOS -- PWS Methodology by Prof. Lawrence Aronhime</p>
142
142
  ```
143
143
 
144
144
  ## Rules
@@ -1,7 +1,7 @@
1
- # User Session: Lawrence + Leah Aronhime -- Blueprint Phase AI Consultancy
1
+ # User Session: Lawrence + an admin-key holder -- Blueprint Phase AI Consultancy
2
2
 
3
3
  **Date:** 2026-04-05
4
- **Users:** Lawrence Aronhime (professor, power user), Leah Aronhime (daughter, new user)
4
+ **Users:** Lawrence Aronhime (professor, power user), an admin-key holder (daughter, new user)
5
5
  **Environment:** macOS, Sonnet 4.6, Claude Pro, v1.7.1
6
6
  **Project:** Blueprint Phase AI Consultancy
7
7
  **Duration:** CLI session ~60min, meeting ~1h57m
@@ -63,7 +63,7 @@
63
63
  ### Participants
64
64
  - **Jonathan Sagir** -- developer, demonstrating MindrianOS
65
65
  - **Lawrence Aronhime** -- professor (Larry model), power user, demonstrating to Leah
66
- - **Leah Aronhime** -- daughter, new user, fashion/design background, has her own Blueprint Phase project
66
+ - **an admin-key holder** -- daughter, new user, fashion/design background, has her own Blueprint Phase project
67
67
 
68
68
  ### Key User Experience Observations
69
69
 
@@ -12,7 +12,10 @@ activation: "env:MINDRIAN_BRAIN_KEY"
12
12
  ## Detection
13
13
 
14
14
  Check Brain availability in order:
15
- 1. `MINDRIAN_BRAIN_KEY` env var (CLI users)
15
+
16
+ **Step 0 -- HTTP-path detection (Phase 123, the standard install).** Run `node $PLUGIN_ROOT/lib/core/resolve-brain-key.cjs` (or in JS: `require('./lib/core/resolve-brain-key.cjs').resolveBrainKey()`). If the resolver returns `available: true`, the Brain is active via the **HTTP path** -- call into `lib/core/brain-client.cjs`'s `query() / search() / schema() / ask()`, NOT an MCP tool. The HTTP path is the standard install path on Claude Code CLI; the MCP path (steps 1-3 below) is an alternative for operators who bundle `mcp-server-brain/` or point an external Neo4j MCP at the canonical `mindrian-brain` server name. The resolver also surfaces SEC-02 permission failures explicitly (`available: false, reason: 'permissions too open: ...'`) -- treat those as "not loaded, user action needed", not as silent unavailability.
17
+
18
+ 1. `MINDRIAN_BRAIN_KEY` env var (CLI users -- subsumed by step 0; kept for legacy detection)
16
19
  2. `mcp__mindrian-brain__brain_schema` tool (Desktop/Cowork MCP)
17
20
  3. `mcp__neo4j-brain__get_neo4j_schema` tool (legacy)
18
21
 
@@ -108,5 +111,8 @@ Always use `brain_ask` first -- natural language, auto-routes Pinecone/Neo4j, ha
108
111
 
109
112
  | Surface | Smart | Neo4j | Pinecone | Schema |
110
113
  |---------|-------|-------|----------|--------|
111
- | mindrian-brain | brain_ask | brain_query | brain_search | brain_schema |
112
- | neo4j-brain (legacy) | N/A | read_neo4j_cypher | search-records | get_neo4j_schema |
114
+ | CLI (HTTP via brain-client.cjs) | `brain-client.ask()` | `brain-client.query()` | `brain-client.search()` | `brain-client.schema()` |
115
+ | mindrian-brain (MCP) | brain_ask | brain_query | brain_search | brain_schema |
116
+ | neo4j-brain (legacy MCP) | N/A | read_neo4j_cypher | search-records | get_neo4j_schema |
117
+
118
+ The first row is the HTTP path (Phase 123 step 0). When `lib/core/resolve-brain-key.cjs` resolves a key, call directly into `lib/core/brain-client.cjs` -- no MCP server required. The bottom two rows are the MCP-path alternatives.