kenaz 0.3.9 → 0.3.11

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 (117) hide show
  1. package/core/.claude/commands/Ansuz.md +12 -16
  2. package/core/.claude/hooks/memory-guard.js +13 -0
  3. package/core/.claude/skills/code_reviewer/SKILL.md +0 -1
  4. package/core/.claude/skills/code_reviewer/patterns.yaml +0 -8
  5. package/core/.claude/skills/dev_agent/SKILL.md +3 -6
  6. package/core/.claude/skills/heimdall/SKILL.md +5 -6
  7. package/core/.claude/skills/huginn/SKILL.md +11 -38
  8. package/core/.collaboration/core/task-api.js +2 -218
  9. package/core/.collaboration/core/task-api.test.js +1 -138
  10. package/core/.formation/bifrost/launch.js +2 -2
  11. package/core/.formation/bifrost/launch.test.js +2 -2
  12. package/core/.formation/bifrost/shared/ansuz-boot-policy.js +3 -3
  13. package/core/.formation/bifrost/shared/codex-injection.js +3 -17
  14. package/core/.formation/bifrost/shared/consolidate.js +1 -51
  15. package/core/.formation/bifrost/sync.js +4 -5
  16. package/core/.formation/tools/__tests__/subagent-bifrost-guard.test.js +1 -1
  17. package/core/.formation/tools/dispatch.js +2 -2
  18. package/core/.formation/tools/kenaz-stats.js +259 -0
  19. package/core/.formation/tools/kenaz-stats.test.js +180 -0
  20. package/core/.formation/tools/mcp-allowlist.test.js +5 -3
  21. package/core/.formation/tools/post-complete/bounded-http.js +1 -40
  22. package/core/.formation/tools/post-complete/bounded-http.test.js +2 -89
  23. package/core/.formation/tools/post-complete/cognitive.js +2 -119
  24. package/core/.formation/tools/post-complete/testing.js +3 -21
  25. package/core/.formation/tools/post-complete.js +2 -428
  26. package/core/.formation/tools/post-complete.test.js +0 -135
  27. package/core/.formation/tools/prompt.js +14 -0
  28. package/core/.formation/tools/route-audit.test.js +8 -20
  29. package/core/.rule/INDEX.yaml +3 -3
  30. package/core/.rule/general/ddx-synapse-stack.yaml +11 -11
  31. package/core/.rule/general/specialist-identity-contract.yaml +5 -5
  32. package/core/.rule/general/synapse-code-intelligence.yaml +25 -111
  33. package/core/.rule/general/worktree-isolation.yaml +2 -2
  34. package/core/.rule/pipeline/task-execution.yaml +6 -9
  35. package/core/.specialist/Amelia/README.md +5 -5
  36. package/core/.specialist/Amelia/capability.yaml +10 -18
  37. package/core/.specialist/Amelia/knowledge.yaml +15 -66
  38. package/core/.specialist/Amelia/workflow.yaml +12 -21
  39. package/core/.specialist/Ansuz/RULES.md +6 -0
  40. package/core/.specialist/Ansuz/capability.yaml +12 -87
  41. package/core/.specialist/Ansuz/concepts/autonomous_agenda.yaml +1 -1
  42. package/core/.specialist/Ansuz/concepts/autonomy_contract.yaml +2 -3
  43. package/core/.specialist/Ansuz/concepts/capability_pointers.yaml +1 -3
  44. package/core/.specialist/Ansuz/concepts/cognitive_fluency_contract.yaml +8 -21
  45. package/core/.specialist/Ansuz/concepts/cognitive_systems_overview.yaml +0 -4
  46. package/core/.specialist/Ansuz/concepts/cognitive_systems_turn_context.yaml +1 -1
  47. package/core/.specialist/Ansuz/concepts/completion_tracking.yaml +0 -1
  48. package/core/.specialist/Ansuz/concepts/deep_knowledge_pointers.yaml +0 -3
  49. package/core/.specialist/Ansuz/concepts/evolvable_guardrails.yaml +3 -3
  50. package/core/.specialist/Ansuz/concepts/fatigue_handoff.yaml +1 -7
  51. package/core/.specialist/Ansuz/concepts/guardrails_immutable.yaml +3 -4
  52. package/core/.specialist/Ansuz/concepts/identity.yaml +1 -2
  53. package/core/.specialist/Ansuz/concepts/phase9_verification.yaml +0 -1
  54. package/core/.specialist/Ansuz/concepts/phase_protocol.yaml +3 -4
  55. package/core/.specialist/Ansuz/core.yaml +3 -6
  56. package/core/.specialist/Ansuz/elixir.yaml +6 -6
  57. package/core/.specialist/Ansuz/exo_cortex_tools.yaml +5 -9
  58. package/core/.specialist/Ansuz/guards/blind_spot_guards.yaml +2 -2
  59. package/core/.specialist/Ansuz/guards/lesson_guards.yaml +6 -19
  60. package/core/.specialist/Ansuz/identity_contract.yaml +4 -4
  61. package/core/.specialist/Ansuz/knowledge.yaml +13 -40
  62. package/core/.specialist/Ansuz/modules/ddx.yaml +2 -2
  63. package/core/.specialist/Ansuz/modules/prophecy.yaml +19 -19
  64. package/core/.specialist/Ansuz/modules/pulse_empty.yaml +6 -17
  65. package/core/.specialist/Ansuz/tools/ansuz-handoff-snapshot.js +3 -102
  66. package/core/.specialist/Ansuz/tools/ansuz-sdk-runner.js +2 -44
  67. package/core/.specialist/Ansuz/workflow.yaml +32 -76
  68. package/core/.specialist/Forseti/core.yaml +2 -7
  69. package/core/.specialist/Forseti/rule.yaml +1 -1
  70. package/core/.specialist/Heimdall/SKILL.md +2 -3
  71. package/core/.specialist/Heimdall/capability.yaml +22 -45
  72. package/core/.specialist/Heimdall/core.yaml +24 -126
  73. package/core/.specialist/Heimdall/principles.yaml +8 -11
  74. package/core/.specialist/Heimdall/rule.yaml +2 -2
  75. package/core/.specialist/Huginn/capability.yaml +31 -52
  76. package/core/.specialist/Huginn/core.yaml +43 -123
  77. package/core/.specialist/Huginn/principles.yaml +5 -5
  78. package/core/.specialist/Huginn/rule.yaml +3 -9
  79. package/core/.specialist/REFLECTION_TO_CONTROL.md +3 -4
  80. package/core/.specialist/shared/guard_schema.json +1 -1
  81. package/core/.specialist/shared/principles.yaml +6 -6
  82. package/core/.specialist/tools/__tests__/task-2409-lessons.test.js +95 -0
  83. package/core/.specialist/tools/ansuz-boot-fast.js +1 -0
  84. package/core/.specialist/tools/lessons.js +234 -0
  85. package/core/.specialist/tools/phase-gate.js +10 -230
  86. package/core/.specialist/tools/phase-gate.test.js +2 -2
  87. package/core/.specialist/tools/prompt-files.test.js +1 -1
  88. package/core/.specialist/tools/session.js +2 -89
  89. package/core/.system/memory/README.md +3 -0
  90. package/core/CLAUDE.md +6 -7
  91. package/core/KENAZ_CORE_VERSION +1 -1
  92. package/core/dev/plans/CLI_FIRST_INSTALL_FLOW.md +26 -0
  93. package/core/plugins/kenaz/INVENTORY.md +1 -1
  94. package/core/plugins/kenaz/commands/Ansuz.md +12 -16
  95. package/core/plugins/kenaz/scripts/kenaz.test.js +2 -1
  96. package/core/plugins/kenaz/scripts/ygg.js +2 -0
  97. package/core/plugins/kenaz/skills/code_reviewer/SKILL.md +0 -1
  98. package/core/plugins/kenaz/skills/code_reviewer/patterns.yaml +0 -8
  99. package/core/plugins/kenaz/skills/dev_agent/SKILL.md +3 -6
  100. package/lib/cli.js +13 -3
  101. package/package.json +6 -6
  102. package/core/.claude/hooks/handoff-snapshot-on-decision.js +0 -188
  103. package/core/.claude/skills/synapse_maintain/SKILL.md +0 -84
  104. package/core/.formation/tools/alaya-gate.js +0 -198
  105. package/core/.formation/tools/post-complete/health.js +0 -464
  106. package/core/.formation/tools/post-complete/task2038.test.js +0 -246
  107. package/core/.formation/tools/post-complete/task2341.test.js +0 -74
  108. package/core/.rule/general/cortex-tools.yaml +0 -181
  109. package/core/.rule/general/memory-language.yaml +0 -67
  110. package/core/.rule/general/memory-source-priority.yaml +0 -207
  111. package/core/.rule/general/synapse-cognitive-fusion.yaml +0 -301
  112. package/core/.specialist/Ansuz/concepts/cognitive_systems_hippocampus.yaml +0 -14
  113. package/core/.specialist/Ansuz/concepts/write_verification.yaml +0 -26
  114. package/core/.specialist/Ansuz/modules/recall.yaml +0 -45
  115. package/core/.specialist/tools/MEMORY_RECALL_TRIGGERS.md +0 -156
  116. package/core/.specialist/tools/context-injection.js +0 -395
  117. package/core/dev/scripts/probe/hippocampus-concurrency.js +0 -247
@@ -17,11 +17,10 @@ const assert = require('assert');
17
17
  const fs = require('fs').promises;
18
18
  const path = require('path');
19
19
  const os = require('os');
20
- const { TaskAPI, CONFIG, parseYAML, toYAML, loadAlayaGate, echoAlayaLessons } = require('./task-api.js');
20
+ const { TaskAPI, CONFIG, parseYAML, toYAML } = require('./task-api.js');
21
21
  // TASK_2104: same shared gate task-api.js loads at runtime — used here only
22
22
  // to read its constants for assertions (query building + gate behavior
23
23
  // itself is covered by prompt.test.js against the one implementation).
24
- const alayaGate = require('../../.formation/tools/alaya-gate.js');
25
24
 
26
25
  // ============================================================================
27
26
  // 測試工具
@@ -1129,140 +1128,4 @@ runner.test('shared-mode: id_alloc stamp on task when local_fallback', async ()
1129
1128
  });
1130
1129
 
1131
1130
 
1132
- // ============================================================================
1133
- // 測試案例: TASK_1992 — Alaya process-lessons echo (create command)
1134
- // ============================================================================
1135
-
1136
- /**
1137
- * Captures console.log calls made during fn() and returns them as an array
1138
- * of joined-argument strings, restoring console.log afterward.
1139
- */
1140
- async function captureLogs(fn) {
1141
- const original = console.log;
1142
- const logs = [];
1143
- console.log = (...a) => logs.push(a.join(' '));
1144
- try {
1145
- await fn();
1146
- } finally {
1147
- console.log = original;
1148
- }
1149
- return logs;
1150
- }
1151
-
1152
- function mcpTextResponse(bodyObj) {
1153
- return {
1154
- ok: true,
1155
- json: async () => ({
1156
- jsonrpc: '2.0', id: 1,
1157
- result: { content: [{ type: 'text', text: JSON.stringify(bodyObj) }] },
1158
- }),
1159
- };
1160
- }
1161
-
1162
- const ALAYA_TASK_DATA = { title: 'Fix appendCortexContext dedup bug', scope_paths: ['.formation/tools/prompt.js'] };
1163
-
1164
- runner.test('alaya-gate buildTaskContextQuery (shared with prompt.js): builds a query from title + scope_paths, null when empty', () => {
1165
- const q = alayaGate.buildTaskContextQuery(ALAYA_TASK_DATA);
1166
- assert.ok(q && q.includes('prompt'));
1167
- assert.strictEqual(alayaGate.buildTaskContextQuery({}), null);
1168
- });
1169
-
1170
- runner.test('echoAlayaLessons: requests the candidate pool with min_cosine, prints up to 3 gated seeds from a mocked fetch', async () => {
1171
- let calledUrl = null;
1172
- let calledOpts = null;
1173
- const fetchMock = async (url, opts) => {
1174
- calledUrl = url;
1175
- calledOpts = opts;
1176
- return mcpTextResponse({
1177
- // js/.formation stack overlap with ALAYA_TASK_DATA's scope_paths, and
1178
- // cosine clears ALAYA_MIN_COSINE_DEFAULT — both must pass the gate.
1179
- bijas: [
1180
- { id: 'a1', seed_type: 'failure_seed', origin: 'local', content: 'Root cause one.', cosine: 0.75, tags: 'js' },
1181
- { id: 'a2', seed_type: 'lesson_seed', origin: 'remote', content: 'Lesson two.', cosine: 0.72, tags: 'js' },
1182
- ],
1183
- mode_effective: 'hybrid',
1184
- });
1185
- };
1186
-
1187
- const logs = await captureLogs(() => echoAlayaLessons(ALAYA_TASK_DATA, fetchMock));
1188
-
1189
- assert.strictEqual(calledUrl, 'http://127.0.0.1:18080/api/mcp');
1190
- const body = JSON.parse(calledOpts.body);
1191
- assert.strictEqual(body.params.name, 'alaya_recall');
1192
- assert.strictEqual(body.params.arguments.mode, 'hybrid');
1193
- assert.deepStrictEqual(body.params.arguments.seed_types, ['failure_seed', 'lesson_seed']);
1194
- assert.strictEqual(body.params.arguments.limit, alayaGate.ALAYA_CANDIDATE_POOL);
1195
- assert.strictEqual(body.params.arguments.min_cosine, alayaGate.ALAYA_MIN_COSINE_DEFAULT);
1196
-
1197
- assert.ok(logs.some(l => l.includes('Alaya lessons for this card:')));
1198
- assert.ok(logs.some(l => l.includes('[failure_seed/local] Root cause one.')));
1199
- assert.ok(logs.some(l => l.includes('[lesson_seed/remote] Lesson two.')));
1200
- });
1201
-
1202
- runner.test('echoAlayaLessons: TASK_2104 gate drops a below-floor bija and never prints it', async () => {
1203
- const fetchMock = async () => mcpTextResponse({
1204
- bijas: [
1205
- // Below ALAYA_MIN_COSINE_DEFAULT (0.70) — must be dropped even though
1206
- // it stack-matches (tags: 'js') and would render fine otherwise.
1207
- { id: 'b1', seed_type: 'failure_seed', origin: 'local', content: 'Stale noise seed.', cosine: 0.5, tags: 'js' },
1208
- ],
1209
- mode_effective: 'hybrid',
1210
- });
1211
- const logs = await captureLogs(() => echoAlayaLessons(ALAYA_TASK_DATA, fetchMock));
1212
- assert.strictEqual(logs.length, 0, 'a below-floor bija must print nothing, not fall back to ungated output');
1213
- });
1214
-
1215
- runner.test('echoAlayaLessons: TASK_2104 gate keeps an above-floor stack-matching bija', async () => {
1216
- const fetchMock = async () => mcpTextResponse({
1217
- bijas: [
1218
- { id: 'c1', seed_type: 'lesson_seed', origin: 'local', content: 'On-topic lesson.', cosine: 0.8, tags: 'js' },
1219
- ],
1220
- mode_effective: 'hybrid',
1221
- });
1222
- const logs = await captureLogs(() => echoAlayaLessons(ALAYA_TASK_DATA, fetchMock));
1223
- assert.ok(logs.some(l => l.includes('[lesson_seed/local] On-topic lesson.')));
1224
- });
1225
-
1226
- runner.test('echoAlayaLessons: gate module unavailable (e.g. sub-project with no .formation/) silently skips, never falls back to ungated output', async () => {
1227
- let fetchCalled = false;
1228
- const fetchMock = async () => { fetchCalled = true; return mcpTextResponse({ bijas: [{ id: 'd1', seed_type: 'failure_seed', origin: 'local', content: 'never printed' }] }); };
1229
- const logs = await captureLogs(() => echoAlayaLessons(ALAYA_TASK_DATA, fetchMock, null));
1230
- assert.strictEqual(logs.length, 0);
1231
- assert.strictEqual(fetchCalled, false, 'must return before ever calling fetch when the gate cannot be loaded');
1232
- });
1233
-
1234
- runner.test('echoAlayaLessons: silent when fetch rejects (network error / timeout)', async () => {
1235
- const fetchMock = async () => { throw new Error('AbortError: The operation was aborted'); };
1236
- const logs = await captureLogs(() => echoAlayaLessons(ALAYA_TASK_DATA, fetchMock));
1237
- assert.strictEqual(logs.length, 0);
1238
- });
1239
-
1240
- runner.test('echoAlayaLessons: silent when fetch resolves non-ok', async () => {
1241
- const fetchMock = async () => ({ ok: false, status: 500 });
1242
- const logs = await captureLogs(() => echoAlayaLessons(ALAYA_TASK_DATA, fetchMock));
1243
- assert.strictEqual(logs.length, 0);
1244
- });
1245
-
1246
- runner.test('echoAlayaLessons: silent when the MCP result has zero bijas', async () => {
1247
- const fetchMock = async () => mcpTextResponse({ bijas: [], mode_effective: 'hybrid' });
1248
- const logs = await captureLogs(() => echoAlayaLessons(ALAYA_TASK_DATA, fetchMock));
1249
- assert.strictEqual(logs.length, 0);
1250
- });
1251
-
1252
- runner.test('echoAlayaLessons: KENAZ_NO_ALAYA_ECHO=1 suppresses the echo entirely (fetch never called)', async () => {
1253
- let fetchCalled = false;
1254
- const fetchMock = async () => { fetchCalled = true; return mcpTextResponse({ bijas: [{ id: 'x', seed_type: 'failure_seed', origin: 'local', content: 'never printed' }] }); };
1255
-
1256
- const prev = process.env.KENAZ_NO_ALAYA_ECHO;
1257
- process.env.KENAZ_NO_ALAYA_ECHO = '1';
1258
- try {
1259
- const logs = await captureLogs(() => echoAlayaLessons(ALAYA_TASK_DATA, fetchMock));
1260
- assert.strictEqual(logs.length, 0);
1261
- assert.strictEqual(fetchCalled, false);
1262
- } finally {
1263
- if (prev === undefined) delete process.env.KENAZ_NO_ALAYA_ECHO;
1264
- else process.env.KENAZ_NO_ALAYA_ECHO = prev;
1265
- }
1266
- });
1267
-
1268
1131
  runner.run();
@@ -276,7 +276,7 @@ function renderMemoryStartupDoc() {
276
276
 
277
277
  function renderOverride(prompt, bootContext, { policy = BOOT_POLICY, projectPath = PROJECT_PATH, memoryStartupDoc = '' } = {}) {
278
278
  const projectInstruction = projectPath
279
- ? `You are working on sub-project: ${projectPath}\nAll task-api.js commands must include --project-path="${projectPath}".\nAll MCP tool calls (synapse_*, hippocampus_*, etc.) must include projectPath="${projectPath}".\n\n`
279
+ ? `You are working on sub-project: ${projectPath}\nAll task-api.js commands must include --project-path="${projectPath}".\nAll MCP tool calls (kenaz_*) must include projectPath="${projectPath}".\n\n`
280
280
  : '';
281
281
  const codexDdxInjection = renderCodexAntiDrift();
282
282
 
@@ -491,7 +491,7 @@ async function main() {
491
491
  ? runFastBoot()
492
492
  : await fetchBootContext({ specialist: SPECIALIST, projectRoot: ROOT, projectPath: PROJECT_PATH || ROOT, includeCanary: false });
493
493
  const offlineNote = probe.reachable ? ''
494
- : '# Boot context availability\nInitial Kenaz MCP probe failed; live recall availability is not established. Local fast boot context is not proof of a successful synapse_status check.\n\n';
494
+ : '# Boot context availability\nInitial Kenaz MCP probe failed; server availability is not established. Local fast boot context is not proof of a successful kenaz_ping check.\n\n';
495
495
  writeOverride(prompt, offlineNote + bootCtx);
496
496
  // ── SessionStart hook (TASK_1230) ─────────────────────────────────────────
497
497
  // Fires after prompt is written (AGENTS.override.md exists) but before Codex
@@ -23,7 +23,7 @@ function mockRequest(scenario = 'offline') {
23
23
  if (scenario === 'incomplete') { res.complete = false; res.emit('close'); return; }
24
24
  if (scenario === 'oversized') { res.emit('data', 'x'.repeat(1024 * 1024 + 1)); return; }
25
25
  const body = {
26
- ok: JSON.stringify({ jsonrpc: '2.0', id: 1, result: { tools: [{ name: 'synapse_status' }] } }),
26
+ ok: JSON.stringify({ jsonrpc: '2.0', id: 1, result: { tools: [{ name: 'kenaz_ping' }] } }),
27
27
  malformed: '{', empty: '{"result":{"tools":[]}}',
28
28
  'rpc-error': '{"error":{"code":-1}}', null: 'null',
29
29
  }[scenario] || '{}';
@@ -135,7 +135,7 @@ test('offline default Ansuz continues once with elixir, truthful status and pinn
135
135
  assert.deepEqual(Array.from(effects.promptCalls[0].args.slice(-2)), ['--project-path', project]);
136
136
  assert.ok(effects.promptCalls[0].args.includes('--external-boot-context'));
137
137
  const override = effects.writes.find(write => write.name.endsWith('AGENTS.override.md'));
138
- assert.match(override.content, /live recall availability is not established/);
138
+ assert.match(override.content, /server availability is not established/);
139
139
  assert.match(override.content, /Fixture fast context banner/);
140
140
  assert.equal((override.content.match(/## Codex Bootstrap Policy \(fast\)/g) || []).length, 1);
141
141
  assert.ok(override.content.includes(`projectPath="${project}"`));
@@ -18,13 +18,13 @@ function resolveBootPolicy({ specialist = 'Ansuz', depth, bootMode, full = false
18
18
  function renderBootstrap({ policy, projectPath, port = '18080', contextual = false } = {}) {
19
19
  const fast = [
20
20
  'Ansuz fast boot (elixir) is the default. This bootstrap policy supersedes any older instruction to run Phase 0, including the Phase 0 sentence inside elixir.',
21
- 'Check synapse_status with the active projectPath when available. If unavailable, report that memory is unavailable and continue only read-only inspection and analysis using local evidence; do not claim recall succeeded.',
21
+ 'Check kenaz_ping with the active projectPath when available. If unavailable, report that the Kenaz server is unavailable and continue only read-only inspection and analysis using local evidence.',
22
22
  'Lightweight Phase 0 uses the supplied boot context and local project evidence; do not run phase-gate Phase 0 or its boot rituals in fast mode. This also supersedes legacy handoff instructions that promise Phase 0 archival. When offline, defer state-changing execution and memory-dependent work until the required service is restored.',
23
23
  'Existing authorization, scope, verification, task tracking, and merge restrictions remain in force.',
24
24
  ].join('\n');
25
25
  const command = `node .specialist/tools/phase-gate.js enter --phase=0 --specialist=${(policy?.specialist || 'Ansuz').toLowerCase()}${projectPath ? ` --project-path="${projectPath}"` : ''}`;
26
- const full = `Before running phase-gate enter, call synapse_status with the active projectPath. If it errors or times out, HALT and emit recovery: confirm Kenaz Dashboard on port ${port}, re-run setup-codex, and restart the Codex session.\nExecute Phase 0 initialization now: run \`${command}\` and follow its checklist.`;
27
- if (contextual) return `## Codex Bootstrap Policy\n\nFor Ansuz without an explicit full boot or legacy depth:\n${fast}\n\nFor explicit --full / --boot-mode full or kernel depth, and for other specialists: retain the full bootstrap guard; call synapse_status before Phase 0 and HALT with recovery instructions if it is unavailable. Use the active specialist and project-path for Phase 0.\n`;
26
+ const full = `Before running phase-gate enter, call kenaz_ping with the active projectPath. If it errors or times out, HALT and emit recovery: confirm Kenaz Dashboard on port ${port}, re-run setup-codex, and restart the Codex session.\nExecute Phase 0 initialization now: run \`${command}\` and follow its checklist.`;
27
+ if (contextual) return `## Codex Bootstrap Policy\n\nFor Ansuz without an explicit full boot or legacy depth:\n${fast}\n\nFor explicit --full / --boot-mode full or kernel depth, and for other specialists: retain the full bootstrap guard; call kenaz_ping before Phase 0 and HALT with recovery instructions if it is unavailable. Use the active specialist and project-path for Phase 0.\n`;
28
28
  return `## Codex Bootstrap Policy (${policy.mode})\n\n${policy.mode === 'fast' ? fast : full}\n`;
29
29
  }
30
30
 
@@ -31,7 +31,7 @@ Guards against failure modes seen in long Codex Ansuz runs (2026-04-09 audit). R
31
31
  ## Anti-Drift 1: DDx First (mechanism before action)
32
32
  Non-trivial problem on first contact:
33
33
  - You MUST enumerate 3 or more competing hypotheses before the first domain-specific tool call.
34
- - You MUST perform recall (synapse_recall / cortex_recall) before acting when memory tools are available.
34
+ - You MUST check the code first (kenaz_lsp_* / Grep) before acting.
35
35
  - You MUST NOT treat the first plausible idea as the plan.
36
36
 
37
37
  Direct attempt is only allowed when one of these is true:
@@ -100,22 +100,8 @@ Never accept an agent's self-report as verification. Phase 9 is NOT optional. Fo
100
100
 
101
101
  Only mark a task complete when EVERY requirement passes its grep/run check. If even one fails, create a FIX task and dispatch it. Half-done is not done.
102
102
 
103
- ## Anti-Drift 8: PROACTIVE LESSON CAPTURE (R-301 alignment)
104
- Proactive lesson capture is mandatory (R-301), so the next session does not rediscover every gotcha.
105
-
106
- When you observe a non-obvious technical fact during a session — bug root cause, surprising tool behavior, infrastructure quirk, workflow trap, performance gotcha — inscribe it as an ash rune IMMEDIATELY without waiting for user prompt.
107
-
108
- Inscription protocol:
109
- 1. Identify the closest STABLE existing code symbol as the rune anchor (file:function:kind format). Bare file paths are weak anchors and may fail FTS5 indexing silently.
110
- 2. \`synapse_inscribe\` with type=ash, confidence>=0.85, content in ENGLISH (MEM-LANG-001 — FTS5 cannot tokenize CJK reliably).
111
- 3. ALWAYS include trigger_phrases (3-5 natural language phrases) for semantic recall.
112
- 4. WRITE-VERIFY: after inscribe, run \`synapse_recall\` with a unique substring from the rune content. If result_count=0, re-inscribe with a different verified symbol_id, OR fall back to writing to .kenaz/specialist/lessons_pending_index.jsonl.
113
-
114
- Anti-patterns to avoid:
115
- - Inscribing on a non-existent symbol_id (silent index failure).
116
- - Skipping write-verify ("trust the success message" — discovered 2026-04-09 that inscribe API can return success while FTS5 indexing does not happen).
117
- - Chinese/CJK content in rune body (FTS5 returns 0 results for CJK queries).
118
- - Generic content ("we hit a bug, fixed it") — provides no recall value.
103
+ ## Anti-Drift 8: PROACTIVE LESSON CAPTURE
104
+ When you observe a non-obvious technical fact (bug root cause, surprising tool behavior, infrastructure quirk, workflow trap), record it immediately with \`kenaz learn add\` — do not wait for the user to ask. Keep it specific; a generic note ("we hit a bug, fixed it") has no recall value.
119
105
 
120
106
  ## Closing Note
121
107
  If a kernel/elixir rule and an Anti-Drift protocol conflict: kernel/elixir wins on identity and safety, Anti-Drift wins on execution and verification.
@@ -131,51 +131,6 @@ function extractEpisodeFromTranscript(filePath){
131
131
  }
132
132
  }
133
133
 
134
- // archiveEpisodeToHippocampus: create+append+close hippocampus episode via MCP HTTP.
135
- // fail-open: any failure returns false without throwing.
136
- // hippocampus_episode_append REQUIRES phase (entry_type is not a valid param — server
137
- // rejects with isError and the episode closes empty). projectPath must be explicit:
138
- // the MCP HTTP layer is stateless and defaults to the dashboard's current project.
139
- async function archiveEpisodeToHippocampus(port,opts,extracted){
140
- try{
141
- var root=resolveRoot(opts);
142
- var scope='Bifrost Codex session'+(opts.sessionId?' '+opts.sessionId:'');
143
- var tags=['bifrost','codex','session_memory'];
144
- var startRes=await mcpCall(port,'hippocampus_episode_start',{
145
- scope:scope,
146
- tags:tags,
147
- source:'bifrost_codex',
148
- projectPath:root
149
- });
150
- var startParsed=mcpToolJson(startRes);
151
- if(!startParsed)return false;
152
- var epId=startParsed.episode_id||startParsed.id;
153
- if(!epId)return false;
154
- var content=extracted?extracted.summary:'Codex session ended (no transcript).';
155
- var ap1=await mcpCall(port,'hippocampus_episode_append',{
156
- episode_id:epId,
157
- content:content,
158
- phase:'summary',
159
- projectPath:root
160
- });
161
- if(!mcpToolJson(ap1))process.stderr.write('[bifrost:consolidate] episode append (summary) failed\n');
162
- if(extracted&&extracted.runeHints&&extracted.runeHints.length){
163
- var ap2=await mcpCall(port,'hippocampus_episode_append',{
164
- episode_id:epId,
165
- content:'Rune candidates: '+extracted.runeHints.join('; '),
166
- phase:'observation',
167
- projectPath:root
168
- });
169
- if(!mcpToolJson(ap2))process.stderr.write('[bifrost:consolidate] episode append (observation) failed\n');
170
- }
171
- await mcpCall(port,'hippocampus_episode_close',{episode_id:epId,projectPath:root});
172
- return true;
173
- }catch(e){
174
- process.stderr.write('[bifrost:consolidate] hippocampus archive error: '+e.message+'\n');
175
- return false;
176
- }
177
- }
178
-
179
134
  // writeHandoff: write ISBAR handoff JSON to the per-session slot (TASK_1829).
180
135
  // Last-writer-wins within a session's own slot only; other sessions' slots are
181
136
  // untouched (per-session isolation replaced the old shared singular slot).
@@ -205,7 +160,7 @@ function writeHandoff(root,opts,extracted){
205
160
  status:'session_ended'
206
161
  },
207
162
  background:{
208
- context:'Codex session ended via Stop hook. Transcript tee and episode archived.',
163
+ context:'Codex session ended via Stop hook. Transcript tee archived.',
209
164
  turn_count:extracted?extracted.turnCount:0
210
165
  },
211
166
  assessment:{
@@ -259,10 +214,6 @@ async function runStopConsolidation(opts){
259
214
  else if(tee&&typeof tee.close==='function')tee.close();
260
215
  var extracted=null;
261
216
  try{extracted=extractEpisodeFromTranscript(transcriptPath);}catch(ee){}
262
- // Episode archive (fail-open)
263
- var epOk=false;
264
- try{epOk=await archiveEpisodeToHippocampus(port,opts||{},extracted);}catch(ae){}
265
- if(!epOk){process.stderr.write('[bifrost:consolidate] hippocampus unavailable or error -- skipping episode.\n');}
266
217
  // Handoff (fail-open)
267
218
  try{writeHandoff(root,opts||{},extracted);}catch(he){}
268
219
  // Heartbeat (fail-open)
@@ -279,7 +230,6 @@ module.exports={
279
230
  mcpCall:mcpCall,
280
231
  mcpToolJson:mcpToolJson,
281
232
  extractEpisodeFromTranscript:extractEpisodeFromTranscript,
282
- archiveEpisodeToHippocampus:archiveEpisodeToHippocampus,
283
233
  writeHandoff:writeHandoff,
284
234
  appendHeartbeat:appendHeartbeat,
285
235
  runStopConsolidation:runStopConsolidation
@@ -57,15 +57,15 @@ function translate(content) {
57
57
  // 4. Replace ToolSearch references (Codex doesn't have this)
58
58
  result = result.replace(
59
59
  /用 `ToolSearch "synapse"` 偵測/g,
60
- '嘗試呼叫 synapse_status 偵測'
60
+ '嘗試呼叫 kenaz_ping 偵測'
61
61
  );
62
62
  result = result.replace(
63
63
  /ToolSearch 未找到 → 該 session 全程降級用 Grep\/Glob/g,
64
- 'synapse_status 失敗 → 該 session 全程降級用 shell 命令搜尋'
64
+ 'kenaz_ping 失敗 → 該 session 全程降級用 shell 命令搜尋'
65
65
  );
66
66
 
67
67
  // 5. Replace Claude Code MCP tool name prefix
68
- // mcp__kenaz-dashboard__synapse_recall → synapse_recall (Codex uses short names)
68
+ // mcp__kenaz-dashboard__kenaz_task_list → kenaz_task_list (Codex uses short names)
69
69
  result = result.replace(/mcp__kenaz-dashboard__/g, '');
70
70
 
71
71
  // 6. Replace /Ansuz, /Amelia etc. slash command references
@@ -85,7 +85,6 @@ ${renderBootstrap({ contextual: true })}
85
85
  ## Project-Path 自動解析
86
86
 
87
87
  當前工作目錄(cwd)即為專案根目錄。所有 MCP 工具呼叫的 \`projectPath\` 參數使用 cwd:
88
- - \`synapse_recall({ query: "...", projectPath: "<cwd>" })\`
89
88
  - \`kenaz_task_list({ projectPath: "<cwd>" })\`
90
89
  - phase-gate.js 指令加上 \`--project-path=<cwd>\`
91
90
 
@@ -97,7 +96,7 @@ ${renderBootstrap({ contextual: true })}
97
96
 
98
97
  本檔案由 Bifröst 從 CLAUDE.md 自動翻譯。以下是 Codex 特有的差異:
99
98
 
100
- 1. **MCP 工具**:透過 \`codex mcp add kenaz-dashboard\` 連接 Dashboard(由 setup-codex.js 自動完成)。所有 Synapse/Hippocampus/Thalamus 工具可直接使用,不需要 \`mcp__kenaz-dashboard__\` 前綴。
99
+ 1. **MCP 工具**:透過 \`codex mcp add kenaz-dashboard\` 連接 Dashboard(由 setup-codex.js 自動完成)。所有 kenaz_* 工具可直接使用,不需要 \`mcp__kenaz-dashboard__\` 前綴。
101
100
  2. **檔案操作**:Codex 使用 shell 命令進行檔案操作,而非 Claude Code 的 Read/Edit/Write 工具。
102
101
  3. **互動式問題**:Codex 沒有 AskUserQuestion 工具,直接用文字詢問用戶即可。
103
102
  4. **Specialist 系統**:若需啟動 Ansuz 等 Specialist,使用 \`node .formation/bifrost/launch.js --specialist Ansuz\`(自動注入 MCP + AGENTS.override.md)。
@@ -139,7 +139,7 @@ setModels({ dispatchModel: 'claude-fable-5', dispatchFamily: 'claude', dispatchM
139
139
  }
140
140
 
141
141
  // ── [7] TASK_1815 model mapping: every emitted model is an enum member ──────
142
- // Covers the NATIVE ids from dashboard/src/lib/models.ts plus the missing-field
142
+ // Covers the NATIVE ids from the retired Dashboard model list (models.ts) plus the missing-field
143
143
  // fallback ('claude-sonnet-4-6', mirrors DEFAULT_DISPATCH_MODEL) and a haiku id
144
144
  // (enum member with no dashboard source entry today — must still map).
145
145
  const MAP_CASES = [
@@ -49,7 +49,7 @@ const DEFAULT_DISPATCH_MODEL = 'claude-sonnet-5-5';
49
49
  * cannot express — the enum has FAMILY names only. So this translation is
50
50
  * structurally LOSSY: claude-opus-5[1m] and claude-opus-4-8[1m] both become
51
51
  * 'opus'. Callers must surface that loss, never treat it as equivalence.
52
- * NOTE: dashboard/src/lib/models.ts `family` ('claude'|'bifrost') is the
52
+ * NOTE: the retired Dashboard model list (models.ts) `family` ('claude'|'bifrost') is the
53
53
  * ADAPTER family and is unrelated to this Claude sub-family mapping.
54
54
  * @param {string} rawModel - dashboard model id, possibly with [1m]-style suffix
55
55
  * @returns {{ model: string|null, lossless: boolean }} model=null → unmappable
@@ -62,7 +62,7 @@ function translateModelForAgentTool(rawModel) {
62
62
  return { model: stripped, lossless: stripped === String(rawModel).trim() };
63
63
  }
64
64
  // claude-<family>[-version...] → <family>. Covers every NATIVE id in
65
- // dashboard/src/lib/models.ts (claude-fable-5-1[1m], claude-opus-5-5[1m],
65
+ // the retired Dashboard model list (models.ts) (claude-fable-5-1[1m], claude-opus-5-5[1m],
66
66
  // claude-fable-5[1m], claude-opus-4-8[1m], claude-sonnet-5,
67
67
  // claude-sonnet-4-6) plus future versions of the same families. 'haiku' has
68
68
  // no dashboard source entry today but maps fine if one appears.