hippo-memory 1.13.5 → 1.15.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 (54) hide show
  1. package/dist/api.d.ts +20 -0
  2. package/dist/api.d.ts.map +1 -1
  3. package/dist/api.js +43 -4
  4. package/dist/api.js.map +1 -1
  5. package/dist/audit.d.ts +1 -1
  6. package/dist/audit.d.ts.map +1 -1
  7. package/dist/audit.js +1 -1
  8. package/dist/audit.js.map +1 -1
  9. package/dist/availability.d.ts +65 -0
  10. package/dist/availability.d.ts.map +1 -0
  11. package/dist/availability.js +94 -0
  12. package/dist/availability.js.map +1 -0
  13. package/dist/cli.d.ts.map +1 -1
  14. package/dist/cli.js +694 -530
  15. package/dist/cli.js.map +1 -1
  16. package/dist/db.d.ts.map +1 -1
  17. package/dist/db.js +556 -472
  18. package/dist/db.js.map +1 -1
  19. package/dist/decisions.d.ts +91 -0
  20. package/dist/decisions.d.ts.map +1 -0
  21. package/dist/decisions.js +278 -0
  22. package/dist/decisions.js.map +1 -0
  23. package/dist/mcp/server.d.ts.map +1 -1
  24. package/dist/mcp/server.js +41 -0
  25. package/dist/mcp/server.js.map +1 -1
  26. package/dist/server.d.ts.map +1 -1
  27. package/dist/server.js +162 -0
  28. package/dist/server.js.map +1 -1
  29. package/dist/src/api.js +43 -4
  30. package/dist/src/api.js.map +1 -1
  31. package/dist/src/audit.js +1 -1
  32. package/dist/src/audit.js.map +1 -1
  33. package/dist/src/availability.js +94 -0
  34. package/dist/src/availability.js.map +1 -0
  35. package/dist/src/cli.js +694 -530
  36. package/dist/src/cli.js.map +1 -1
  37. package/dist/src/db.js +556 -472
  38. package/dist/src/db.js.map +1 -1
  39. package/dist/src/decisions.js +278 -0
  40. package/dist/src/decisions.js.map +1 -0
  41. package/dist/src/mcp/server.js +41 -0
  42. package/dist/src/mcp/server.js.map +1 -1
  43. package/dist/src/server.js +162 -0
  44. package/dist/src/server.js.map +1 -1
  45. package/dist/src/version.js +1 -1
  46. package/dist/src/version.js.map +1 -1
  47. package/dist/version.d.ts +1 -1
  48. package/dist/version.d.ts.map +1 -1
  49. package/dist/version.js +1 -1
  50. package/dist/version.js.map +1 -1
  51. package/extensions/openclaw-plugin/openclaw.plugin.json +46 -46
  52. package/extensions/openclaw-plugin/package.json +15 -13
  53. package/openclaw.plugin.json +45 -45
  54. package/package.json +75 -75
package/dist/cli.js CHANGED
@@ -31,7 +31,7 @@ import * as os from 'os';
31
31
  import { fileURLToPath } from 'node:url';
32
32
  import { execFileSync, execSync, spawn } from 'child_process';
33
33
  import { installJsonHooks, uninstallJsonHooks, resolveJsonHookPaths, detectInstalledTools, defaultSleepLogPath, ensureCodexWrapperInstalled, installCodexWrapper, uninstallCodexWrapper, resolveCodexSessionTranscript, resolveCodexWrapperPaths, installOpencodePlugin, uninstallOpencodePlugin, resolveOpencodePluginPath, } from './hooks.js';
34
- import { createMemory, calculateStrength, calculateRewardFactor, deriveHalfLife, resolveConfidence, computeSchemaFit, Layer, DECISION_HALF_LIFE_DAYS, } from './memory.js';
34
+ import { createMemory, calculateStrength, calculateRewardFactor, deriveHalfLife, resolveConfidence, computeSchemaFit, Layer, } from './memory.js';
35
35
  import { getHippoRoot, isInitialized, initStore, writeEntry, readEntry, deleteEntry, loadAllEntries, loadSearchEntries, loadIndex, saveIndex, loadStats, updateStats, saveActiveTaskSnapshot, loadActiveTaskSnapshot, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, resolveConflict, saveSessionHandoff, loadLatestHandoff, loadHandoffById, RECALL_DEFAULT_DENY_SCOPES, } from './store.js';
36
36
  import { markRetrieved, hybridSearch, physicsSearch, explainMatch, textOverlap } from './search.js';
37
37
  import { renderTraceContent, parseSteps } from './trace.js';
@@ -58,8 +58,10 @@ import { buildCorrectionLatency } from './correction-latency.js';
58
58
  import * as api from './api.js';
59
59
  import * as predictionsModule from './predictions.js';
60
60
  import { computePlanningFallacyOutput } from './predictions.js';
61
+ import * as decisionsModule from './decisions.js';
61
62
  import { createHash } from 'node:crypto';
62
63
  import { detectAnchoring, hashQueryText, buildSessionKey, getOrCreateRing, appendRecall, snapshotRing, } from './recall-history.js';
64
+ import { detectAvailabilityBias } from './availability.js';
63
65
  // v0.33 / J1 — Module-level per-(tenant, session) recall-history ring map.
64
66
  // Each CLI process maintains its OWN Map; no IPC / no cross-process sharing
65
67
  // (plan v3 decision: per-pipeline rings, see docs/plans/2026-05-26-j1-anchoring-detector.md).
@@ -1106,6 +1108,27 @@ async function cmdRecall(hippoRoot, query, flags) {
1106
1108
  memory_id: cmdAnchoringHint.memoryId,
1107
1109
  });
1108
1110
  }
1111
+ // v1.13.x / J2 — CLI per-pipeline availability/recency-bias detector. Each
1112
+ // pipeline computes its own hint (this one against the CLI's returned top-K
1113
+ // and the full local+global candidate pool). Soft warning only. Gated by
1114
+ // HIPPO_AVAILABILITY=off, which short-circuits BEFORE the detect call so
1115
+ // disabled tenants pay zero work. Audit emission is pipeline-local, lockstep
1116
+ // with the anchoring emitCliAudit calls above. cmdAvailabilityHint is null on
1117
+ // the zero-result branch (topK < minReturned), so the splat is a no-op there.
1118
+ let cmdAvailabilityHint = null;
1119
+ if (process.env.HIPPO_AVAILABILITY !== 'off') {
1120
+ cmdAvailabilityHint = detectAvailabilityBias({
1121
+ topK: results.map((r) => ({ id: r.entry.id, created: r.entry.created })),
1122
+ pool: [...localEntries, ...globalEntries].map((e) => ({ id: e.id, created: e.created })),
1123
+ });
1124
+ if (cmdAvailabilityHint) {
1125
+ emitCliAudit(hippoRoot, 'recall_availability_detected', undefined, {
1126
+ recent_fraction: cmdAvailabilityHint.recentFraction,
1127
+ older_passed_over: cmdAvailabilityHint.olderCandidatesPassedOver,
1128
+ returned_count: cmdAvailabilityHint.returnedCount,
1129
+ });
1130
+ }
1131
+ }
1109
1132
  // v0.32 / J3.2 — auto-injection of reference-class baserate when the
1110
1133
  // CLI query carries a forward-prediction phrase AND a class matches.
1111
1134
  // cmdRecall runs its own pipeline (doesn't go through api.recall for
@@ -1213,6 +1236,7 @@ async function cmdRecall(hippoRoot, query, flags) {
1213
1236
  ...(cmdPlanningFallacyHint ? { planningFallacyHint: cmdPlanningFallacyHint } : {}),
1214
1237
  ...(cmdPlanningFallacyWatching ? { planningFallacyWatching: cmdPlanningFallacyWatching } : {}),
1215
1238
  ...(cmdAnchoringHint ? { anchoringHint: cmdAnchoringHint } : {}),
1239
+ ...(cmdAvailabilityHint ? { availabilityHint: cmdAvailabilityHint } : {}),
1216
1240
  };
1217
1241
  if (includeContinuity) {
1218
1242
  out.continuity = {
@@ -1230,6 +1254,13 @@ async function cmdRecall(hippoRoot, query, flags) {
1230
1254
  if (cmdAnchoringHint) {
1231
1255
  console.log(`[anchored_on: ${cmdAnchoringHint.memoryId}] ${cmdAnchoringHint.summary}`);
1232
1256
  }
1257
+ // v1.13.x / J2 — render availability/recency-bias hint below anchoring and
1258
+ // above the planning-fallacy hint. Soft warning; absent (env disabled or no
1259
+ // bias detected) is silent. Null on this zero-result branch anyway since
1260
+ // topK < minReturned, so this is effectively a no-op here; wired for parity.
1261
+ if (cmdAvailabilityHint) {
1262
+ console.log(`Availability bias (${cmdAvailabilityHint.recentCount}/${cmdAvailabilityHint.returnedCount} recent): ${cmdAvailabilityHint.summary}`);
1263
+ }
1233
1264
  // v0.32 / J3.2 — render hint BEFORE the no-memories message so the
1234
1265
  // calling agent sees its track record even when the query missed
1235
1266
  // every memory. Same single-line shape + JSON.stringify-safe phrase
@@ -1314,6 +1345,7 @@ async function cmdRecall(hippoRoot, query, flags) {
1314
1345
  ...(cmdPlanningFallacyHint ? { planningFallacyHint: cmdPlanningFallacyHint } : {}),
1315
1346
  ...(cmdPlanningFallacyWatching ? { planningFallacyWatching: cmdPlanningFallacyWatching } : {}),
1316
1347
  ...(cmdAnchoringHint ? { anchoringHint: cmdAnchoringHint } : {}),
1348
+ ...(cmdAvailabilityHint ? { availabilityHint: cmdAvailabilityHint } : {}),
1317
1349
  };
1318
1350
  if (includeContinuity) {
1319
1351
  jsonOut.continuity = {
@@ -1343,6 +1375,13 @@ async function cmdRecall(hippoRoot, query, flags) {
1343
1375
  console.log(`[anchored_on: ${cmdAnchoringHint.memoryId}] ${cmdAnchoringHint.summary}`);
1344
1376
  console.log();
1345
1377
  }
1378
+ // v1.13.x / J2 — render availability/recency-bias hint below anchoring and
1379
+ // above the planning-fallacy hint. Soft warning; absent (env disabled or no
1380
+ // bias detected) is silent.
1381
+ if (cmdAvailabilityHint) {
1382
+ console.log(`Availability bias (${cmdAvailabilityHint.recentCount}/${cmdAvailabilityHint.returnedCount} recent): ${cmdAvailabilityHint.summary}`);
1383
+ console.log();
1384
+ }
1346
1385
  // v0.32 / J3.2 — render planning-fallacy hint ABOVE the result list so
1347
1386
  // the agent sees its track record before scrolling. Hint absent (env
1348
1387
  // disabled or no forward-claim match) is silent. detectedPhrase is
@@ -3264,6 +3303,166 @@ function cmdPredict(hippoRoot, args, flags) {
3264
3303
  if (created.memoryId)
3265
3304
  console.log(` memory: ${created.memoryId}`);
3266
3305
  }
3306
+ function cmdDecide(hippoRoot, args, flags) {
3307
+ requireInit(hippoRoot);
3308
+ const tenantId = resolveTenantId({});
3309
+ const subcommand = args[0] ?? '';
3310
+ if (subcommand === 'list') {
3311
+ const statusRaw = flags['status'];
3312
+ const status = typeof statusRaw === 'string' ? statusRaw.trim() : 'all';
3313
+ const limitRaw = flags['limit'];
3314
+ const limit = limitRaw !== undefined ? parseInt(String(limitRaw), 10) : 100;
3315
+ if (!Number.isFinite(limit) || limit <= 0) {
3316
+ console.error(`Invalid --limit: "${limitRaw}". Must be a positive integer.`);
3317
+ process.exit(1);
3318
+ }
3319
+ let results;
3320
+ if (status === 'all') {
3321
+ results = decisionsModule.loadDecisions(hippoRoot, tenantId, { limit });
3322
+ }
3323
+ else {
3324
+ if (!decisionsModule.VALID_DECISION_STATES.has(status)) {
3325
+ console.error(`Invalid --status: "${status}". Must be one of: active | superseded | closed | all.`);
3326
+ process.exit(1);
3327
+ }
3328
+ results = decisionsModule.loadDecisions(hippoRoot, tenantId, {
3329
+ status: status,
3330
+ limit,
3331
+ });
3332
+ }
3333
+ if (results.length === 0) {
3334
+ console.log('No decisions.');
3335
+ return;
3336
+ }
3337
+ console.log(`Found ${results.length} decisions:\n`);
3338
+ for (const d of results) {
3339
+ const supPart = d.supersededBy !== null ? ` superseded_by=#${d.supersededBy}` : '';
3340
+ console.log(`#${d.id} [${d.status}]${supPart} memory=${d.memoryId ?? '-'}`);
3341
+ console.log(` ${d.decisionText}`);
3342
+ if (d.context)
3343
+ console.log(` context: ${d.context}`);
3344
+ }
3345
+ return;
3346
+ }
3347
+ if (subcommand === 'get') {
3348
+ const idRaw = args[1];
3349
+ if (!idRaw) {
3350
+ console.error('Usage: hippo decide get <id>');
3351
+ process.exit(1);
3352
+ }
3353
+ const id = parseInt(String(idRaw), 10);
3354
+ if (!Number.isFinite(id) || id <= 0) {
3355
+ console.error(`Invalid decision id: "${idRaw}"`);
3356
+ process.exit(1);
3357
+ }
3358
+ const decision = decisionsModule.loadDecisionById(hippoRoot, tenantId, id);
3359
+ if (!decision) {
3360
+ console.error(`Decision ${id} not found.`);
3361
+ process.exit(1);
3362
+ }
3363
+ console.log(`Decision #${decision.id}`);
3364
+ console.log(` status: ${decision.status}`);
3365
+ console.log(` text: ${decision.decisionText}`);
3366
+ if (decision.context)
3367
+ console.log(` context: ${decision.context}`);
3368
+ if (decision.supersededBy !== null)
3369
+ console.log(` superseded_by: #${decision.supersededBy}`);
3370
+ if (decision.supersededAt)
3371
+ console.log(` superseded_at: ${decision.supersededAt}`);
3372
+ if (decision.closedAt)
3373
+ console.log(` closed_at: ${decision.closedAt}`);
3374
+ if (decision.memoryId)
3375
+ console.log(` memory: ${decision.memoryId}`);
3376
+ console.log(` created: ${decision.createdAt}`);
3377
+ return;
3378
+ }
3379
+ if (subcommand === 'close') {
3380
+ const idRaw = args[1];
3381
+ if (!idRaw) {
3382
+ console.error('Usage: hippo decide close <id>');
3383
+ process.exit(1);
3384
+ }
3385
+ const id = parseInt(String(idRaw), 10);
3386
+ if (!Number.isFinite(id) || id <= 0) {
3387
+ console.error(`Invalid decision id: "${idRaw}"`);
3388
+ process.exit(1);
3389
+ }
3390
+ const closed = decisionsModule.closeDecision(hippoRoot, tenantId, id);
3391
+ console.log(`Decision #${closed.id} closed.`);
3392
+ return;
3393
+ }
3394
+ // Default subcommand: create. args[0] is the decision text.
3395
+ const decisionText = subcommand;
3396
+ if (!decisionText) {
3397
+ console.error('Usage: hippo decide "<decision>" [--context "<why>"] [--supersedes <memory-id>]');
3398
+ console.error(' hippo decide list [--status active|superseded|closed|all] [--limit N]');
3399
+ console.error(' hippo decide get <id>');
3400
+ console.error(' hippo decide close <id>');
3401
+ process.exit(1);
3402
+ }
3403
+ const contextRaw = flags['context'];
3404
+ const context = typeof contextRaw === 'string' && contextRaw ? contextRaw : undefined;
3405
+ // A value-less `--supersedes` (parseArgs stores boolean true) is a malformed
3406
+ // request: the user asked to supersede but gave no memory id. Reject it rather
3407
+ // than silently creating a non-superseding decision (codex review 2026-05-28).
3408
+ if (flags['supersedes'] === true) {
3409
+ console.error('--supersedes requires a memory id, e.g. hippo decide "<text>" --supersedes mem_abc123.');
3410
+ process.exit(1);
3411
+ }
3412
+ const supersedesMemId = typeof flags['supersedes'] === 'string' ? flags['supersedes'] : null;
3413
+ // Backward-compat: --supersedes takes a MEMORY id. Validate it exists and
3414
+ // resolve it to the active decision row (if any). Grill fix: commit the
3415
+ // canonical table create+supersede FIRST (inside saveDecision's SAVEPOINT),
3416
+ // weaken the old memory LAST (best-effort) so a memory-write failure cannot
3417
+ // leave the memory stale without the table reflecting the supersession.
3418
+ let supersedesDecisionId;
3419
+ let oldEntry = null;
3420
+ if (supersedesMemId) {
3421
+ oldEntry = readEntry(hippoRoot, supersedesMemId, tenantId) ?? null;
3422
+ if (!oldEntry) {
3423
+ console.error(`Memory ${supersedesMemId} not found.`);
3424
+ process.exit(1);
3425
+ }
3426
+ supersedesDecisionId =
3427
+ decisionsModule.resolveActiveDecisionIdByMemory(hippoRoot, tenantId, supersedesMemId) ?? undefined;
3428
+ }
3429
+ const decisionPathTags = extractPathTags(process.cwd());
3430
+ const created = decisionsModule.saveDecision(hippoRoot, tenantId, {
3431
+ decisionText,
3432
+ context,
3433
+ supersedesDecisionId,
3434
+ extraTags: decisionPathTags,
3435
+ });
3436
+ // Legacy memory-weaken (best-effort, LAST): half-life halved, marked stale +
3437
+ // 'superseded' tag. Preserves the exact pre-promotion behavior for the memory
3438
+ // mirror; the canonical table supersession already committed above.
3439
+ if (oldEntry) {
3440
+ // Best-effort: saveDecision already committed the canonical mutation (new
3441
+ // decision created + old row superseded). If this legacy memory-weaken
3442
+ // throws, do NOT fail the command — a retry would find no active decision
3443
+ // for the old memory and create a duplicate active successor. Warn instead
3444
+ // (codex review 2026-05-28).
3445
+ try {
3446
+ oldEntry.half_life_days = Math.max(1, Math.floor(oldEntry.half_life_days / 2));
3447
+ oldEntry.confidence = 'stale';
3448
+ if (!oldEntry.tags.includes('superseded'))
3449
+ oldEntry.tags.push('superseded');
3450
+ writeEntry(hippoRoot, oldEntry);
3451
+ }
3452
+ catch (e) {
3453
+ console.error(` warning: decision recorded and superseded, but failed to weaken the prior memory ${supersedesMemId}: ${e.message}`);
3454
+ }
3455
+ }
3456
+ console.log(`Decision recorded: #${created.id}`);
3457
+ if (created.memoryId)
3458
+ console.log(` memory: ${created.memoryId}`);
3459
+ if (supersedesMemId) {
3460
+ const tail = supersedesDecisionId !== undefined
3461
+ ? ` (decision #${supersedesDecisionId} superseded)`
3462
+ : ' (no active decision row; memory weakened only)';
3463
+ console.log(` supersedes memory: ${supersedesMemId}${tail}`);
3464
+ }
3465
+ }
3267
3466
  function cmdCurrent(hippoRoot, args, flags) {
3268
3467
  requireInit(hippoRoot);
3269
3468
  const subcommand = args[0] ?? 'show';
@@ -3830,166 +4029,166 @@ const HOOKS = {
3830
4029
  'claude-code': {
3831
4030
  file: 'CLAUDE.md',
3832
4031
  description: 'Claude Code',
3833
- content: `
3834
- ## Project Memory (Hippo)
3835
-
3836
- Before starting work, load relevant context:
3837
- \`\`\`bash
3838
- hippo context --auto --budget 1500
3839
- \`\`\`
3840
-
3841
- When you learn something important:
3842
- \`\`\`bash
3843
- hippo remember "<lesson>"
3844
- \`\`\`
3845
-
3846
- When you hit an error or discover a gotcha:
3847
- \`\`\`bash
3848
- hippo remember "<what went wrong and why>" --error
3849
- \`\`\`
3850
-
3851
- After completing work successfully:
3852
- \`\`\`bash
3853
- hippo outcome --good
3854
- \`\`\`
3855
-
3856
- When the user ends the session, capture a brief summary:
3857
- \`\`\`bash
3858
- hippo capture --stdin <<< '<decisions, errors, lessons — 2-5 bullets>'
3859
- \`\`\`
4032
+ content: `
4033
+ ## Project Memory (Hippo)
4034
+
4035
+ Before starting work, load relevant context:
4036
+ \`\`\`bash
4037
+ hippo context --auto --budget 1500
4038
+ \`\`\`
4039
+
4040
+ When you learn something important:
4041
+ \`\`\`bash
4042
+ hippo remember "<lesson>"
4043
+ \`\`\`
4044
+
4045
+ When you hit an error or discover a gotcha:
4046
+ \`\`\`bash
4047
+ hippo remember "<what went wrong and why>" --error
4048
+ \`\`\`
4049
+
4050
+ After completing work successfully:
4051
+ \`\`\`bash
4052
+ hippo outcome --good
4053
+ \`\`\`
4054
+
4055
+ When the user ends the session, capture a brief summary:
4056
+ \`\`\`bash
4057
+ hippo capture --stdin <<< '<decisions, errors, lessons — 2-5 bullets>'
4058
+ \`\`\`
3860
4059
  `.trim(),
3861
4060
  },
3862
4061
  'codex': {
3863
4062
  file: 'AGENTS.md',
3864
4063
  description: 'OpenAI Codex',
3865
- content: `
3866
- ## Project Memory (Hippo)
3867
-
3868
- At the start of every task, run:
3869
- \`\`\`bash
3870
- hippo context --auto --budget 1500
3871
- \`\`\`
3872
- Read the output before writing any code.
3873
-
3874
- On errors or unexpected behaviour:
3875
- \`\`\`bash
3876
- hippo remember "<description of what went wrong>" --error
3877
- \`\`\`
3878
-
3879
- On task completion:
3880
- \`\`\`bash
3881
- hippo outcome --good
3882
- \`\`\`
3883
-
3884
- When Hippo's Codex wrapper is installed, session-end capture runs automatically.
3885
- If the wrapper is not installed, capture a brief summary manually:
3886
- \`\`\`bash
3887
- hippo capture --stdin <<< '<decisions, errors, lessons — 2-5 bullets>'
3888
- \`\`\`
4064
+ content: `
4065
+ ## Project Memory (Hippo)
4066
+
4067
+ At the start of every task, run:
4068
+ \`\`\`bash
4069
+ hippo context --auto --budget 1500
4070
+ \`\`\`
4071
+ Read the output before writing any code.
4072
+
4073
+ On errors or unexpected behaviour:
4074
+ \`\`\`bash
4075
+ hippo remember "<description of what went wrong>" --error
4076
+ \`\`\`
4077
+
4078
+ On task completion:
4079
+ \`\`\`bash
4080
+ hippo outcome --good
4081
+ \`\`\`
4082
+
4083
+ When Hippo's Codex wrapper is installed, session-end capture runs automatically.
4084
+ If the wrapper is not installed, capture a brief summary manually:
4085
+ \`\`\`bash
4086
+ hippo capture --stdin <<< '<decisions, errors, lessons — 2-5 bullets>'
4087
+ \`\`\`
3889
4088
  `.trim(),
3890
4089
  },
3891
4090
  'cursor': {
3892
4091
  file: '.cursorrules',
3893
4092
  description: 'Cursor',
3894
- content: `
3895
- # Project Memory (Hippo)
3896
- # Before each task, load context:
3897
- # hippo context --auto --budget 1500
3898
- # After errors:
3899
- # hippo remember "<error description>" --error
3900
- # After completing:
3901
- # hippo outcome --good
4093
+ content: `
4094
+ # Project Memory (Hippo)
4095
+ # Before each task, load context:
4096
+ # hippo context --auto --budget 1500
4097
+ # After errors:
4098
+ # hippo remember "<error description>" --error
4099
+ # After completing:
4100
+ # hippo outcome --good
3902
4101
  `.trim(),
3903
4102
  },
3904
4103
  'openclaw': {
3905
4104
  file: 'AGENTS.md',
3906
4105
  description: 'OpenClaw',
3907
- content: `
3908
- ## Project Memory (Hippo)
3909
-
3910
- At the start of every session, run:
3911
- \`\`\`bash
3912
- hippo context --auto --budget 1500
3913
- \`\`\`
3914
- Read the output before writing any code.
3915
-
3916
- On errors or unexpected behaviour:
3917
- \`\`\`bash
3918
- hippo remember "<description of what went wrong>" --error
3919
- \`\`\`
3920
-
3921
- On task completion:
3922
- \`\`\`bash
3923
- hippo outcome --good
3924
- \`\`\`
3925
-
3926
- When ending a session, capture a brief summary:
3927
- \`\`\`bash
3928
- hippo capture --stdin <<< '<decisions, errors, lessons — 2-5 bullets>'
3929
- \`\`\`
4106
+ content: `
4107
+ ## Project Memory (Hippo)
4108
+
4109
+ At the start of every session, run:
4110
+ \`\`\`bash
4111
+ hippo context --auto --budget 1500
4112
+ \`\`\`
4113
+ Read the output before writing any code.
4114
+
4115
+ On errors or unexpected behaviour:
4116
+ \`\`\`bash
4117
+ hippo remember "<description of what went wrong>" --error
4118
+ \`\`\`
4119
+
4120
+ On task completion:
4121
+ \`\`\`bash
4122
+ hippo outcome --good
4123
+ \`\`\`
4124
+
4125
+ When ending a session, capture a brief summary:
4126
+ \`\`\`bash
4127
+ hippo capture --stdin <<< '<decisions, errors, lessons — 2-5 bullets>'
4128
+ \`\`\`
3930
4129
  `.trim(),
3931
4130
  },
3932
4131
  'opencode': {
3933
4132
  file: 'AGENTS.md',
3934
4133
  description: 'OpenCode',
3935
- content: `
3936
- ## Project Memory (Hippo)
3937
-
3938
- At the start of every task, run:
3939
- \`\`\`bash
3940
- hippo context --auto --budget 1500
3941
- \`\`\`
3942
- Read the output before writing any code.
3943
-
3944
- When you learn something important or hit an error:
3945
- \`\`\`bash
3946
- hippo remember "<lesson>" --error
3947
- \`\`\`
3948
-
3949
- When stuck or repeating yourself, check if this happened before:
3950
- \`\`\`bash
3951
- hippo recall "<what's going wrong>" --budget 2000
3952
- \`\`\`
3953
-
3954
- On task completion:
3955
- \`\`\`bash
3956
- hippo outcome --good
3957
- \`\`\`
3958
-
3959
- When ending a session, capture a brief summary:
3960
- \`\`\`bash
3961
- hippo capture --stdin <<< '<decisions, errors, lessons — 2-5 bullets>'
3962
- \`\`\`
4134
+ content: `
4135
+ ## Project Memory (Hippo)
4136
+
4137
+ At the start of every task, run:
4138
+ \`\`\`bash
4139
+ hippo context --auto --budget 1500
4140
+ \`\`\`
4141
+ Read the output before writing any code.
4142
+
4143
+ When you learn something important or hit an error:
4144
+ \`\`\`bash
4145
+ hippo remember "<lesson>" --error
4146
+ \`\`\`
4147
+
4148
+ When stuck or repeating yourself, check if this happened before:
4149
+ \`\`\`bash
4150
+ hippo recall "<what's going wrong>" --budget 2000
4151
+ \`\`\`
4152
+
4153
+ On task completion:
4154
+ \`\`\`bash
4155
+ hippo outcome --good
4156
+ \`\`\`
4157
+
4158
+ When ending a session, capture a brief summary:
4159
+ \`\`\`bash
4160
+ hippo capture --stdin <<< '<decisions, errors, lessons — 2-5 bullets>'
4161
+ \`\`\`
3963
4162
  `.trim(),
3964
4163
  },
3965
4164
  'pi': {
3966
4165
  file: 'AGENTS.md',
3967
4166
  description: 'Pi',
3968
- content: `
3969
- ## Project Memory (Hippo)
3970
-
3971
- At the start of every session, run:
3972
- \`\`\`bash
3973
- hippo context --auto --budget 1500
3974
- \`\`\`
3975
- Read the output before writing any code.
3976
-
3977
- On errors or unexpected behaviour:
3978
- \`\`\`bash
3979
- hippo remember "<description of what went wrong>" --error
3980
- \`\`\`
3981
-
3982
- On task completion:
3983
- \`\`\`bash
3984
- hippo outcome --good
3985
- \`\`\`
3986
-
3987
- When ending a session, capture a brief summary:
3988
- \`\`\`bash
3989
- hippo capture --stdin <<< '<decisions, errors, lessons — 2-5 bullets>'
3990
- \`\`\`
3991
-
3992
- For full integration, copy the hippo-memory Pi extension to \`~/.pi/agent/extensions/hippo-memory/\`.
4167
+ content: `
4168
+ ## Project Memory (Hippo)
4169
+
4170
+ At the start of every session, run:
4171
+ \`\`\`bash
4172
+ hippo context --auto --budget 1500
4173
+ \`\`\`
4174
+ Read the output before writing any code.
4175
+
4176
+ On errors or unexpected behaviour:
4177
+ \`\`\`bash
4178
+ hippo remember "<description of what went wrong>" --error
4179
+ \`\`\`
4180
+
4181
+ On task completion:
4182
+ \`\`\`bash
4183
+ hippo outcome --good
4184
+ \`\`\`
4185
+
4186
+ When ending a session, capture a brief summary:
4187
+ \`\`\`bash
4188
+ hippo capture --stdin <<< '<decisions, errors, lessons — 2-5 bullets>'
4189
+ \`\`\`
4190
+
4191
+ For full integration, copy the hippo-memory Pi extension to \`~/.pi/agent/extensions/hippo-memory/\`.
3993
4192
  `.trim(),
3994
4193
  },
3995
4194
  };
@@ -4677,6 +4876,10 @@ const VALID_AUDIT_OPS = new Set([
4677
4876
  'recall_anchor_detected_query_repeat', // v0.33 / J1 — emitted by detector on R1 fire
4678
4877
  'recall_anchor_detected_memory_dominance', // v0.33 / J1 — emitted by detector on R2 fire
4679
4878
  'recall_anchor_skipped_no_session', // v0.33 / J1 — telemetry: no sessionId, ring skipped
4879
+ 'recall_availability_detected', // v1.13.x / J2 - emitted when availability/recency-bias hint fires
4880
+ 'decision_create', // E2 decision first-class object — emitted by saveDecision
4881
+ 'decision_supersede', // E2 — emitted by saveDecision when --supersedes resolves to an active decision row
4882
+ 'decision_close', // E2 — emitted by closeDecision
4680
4883
  ]);
4681
4884
  function formatAuditRow(ev) {
4682
4885
  const target = ev.targetId ?? '-';
@@ -4882,12 +5085,12 @@ function cmdGoalPush(hippoRoot, args, flags) {
4882
5085
  function listAllGoals(hippoRoot, sessionId, tenantId) {
4883
5086
  const db = openHippoDb(hippoRoot);
4884
5087
  try {
4885
- const rows = db.prepare(`
4886
- SELECT id, session_id, tenant_id, goal_name, level, parent_goal_id, status,
4887
- success_condition, retrieval_policy_id, created_at, completed_at, outcome_score
4888
- FROM goal_stack
4889
- WHERE tenant_id = ? AND session_id = ?
4890
- ORDER BY created_at ASC
5088
+ const rows = db.prepare(`
5089
+ SELECT id, session_id, tenant_id, goal_name, level, parent_goal_id, status,
5090
+ success_condition, retrieval_policy_id, created_at, completed_at, outcome_score
5091
+ FROM goal_stack
5092
+ WHERE tenant_id = ? AND session_id = ?
5093
+ ORDER BY created_at ASC
4891
5094
  `).all(tenantId, sessionId);
4892
5095
  return rows.map(rowToGoal);
4893
5096
  }
@@ -5210,349 +5413,353 @@ function cmdSlack(hippoRoot, args, flags) {
5210
5413
  process.exit(1);
5211
5414
  }
5212
5415
  function printUsage() {
5213
- console.log(`
5214
- Hippo - biologically-inspired memory system for AI agents
5215
-
5216
- Usage: hippo <command> [options]
5217
-
5218
- Commands:
5219
- init Create .hippo/ structure in current directory
5220
- --scan [dir] Find all git repos under dir (default: ~) and init each
5221
- --days <n> Days of git history to seed (default: 365 for --scan, 30 for single)
5222
- --global Init the global store ($HIPPO_HOME or ~/.hippo/)
5223
- --no-hooks Skip auto-detecting and installing agent hooks
5224
- --no-schedule Skip auto-creating the machine-level daily runner
5225
- --no-learn Skip seeding memories from git history
5226
- remember <text> Store a memory
5227
- --tag <tag> Add a tag (repeatable)
5228
- --error Tag as error (boosts retention)
5229
- --pin Pin memory (never decays)
5230
- --verified Set confidence: verified (default)
5231
- --observed Set confidence: observed
5232
- --inferred Set confidence: inferred
5233
- --global Store in global store ($HIPPO_HOME or ~/.hippo/)
5234
- recall <query> Search and retrieve memories (local + global)
5235
- --budget <n> Token budget (default: 4000)
5236
- --min-results <n> Minimum results regardless of budget (default: 1)
5237
- --json Output as JSON
5238
- --why Show match reasons and source annotations
5239
- --no-mmr Disable MMR diversity re-ranking
5240
- --mmr-lambda <f> MMR balance 0..1 (default: 0.7, 1.0 = pure relevance)
5241
- --evc-adaptive ACC-style: when top-K shows high inter-item overlap
5242
- (= conflict cluster), expand pool and re-rank by
5243
- recency. Default off. RESEARCH.md §PFC.ACC.
5244
- --filter-conflicts vlPFC interference filter: drop superseded entries
5245
- and 0.3x-downweight entries flagged in an open
5246
- conflict with a peer in the same result set.
5247
- Uses recorded supersession + conflicts only — never
5248
- lexical inference. Default off. RESEARCH.md §PFC.vlPFC.
5249
- --value-aware vmPFC value attribution: boost memories with positive
5250
- cumulative outcomes and demote those with negative
5251
- outcomes during ranking. Multiplier
5252
- clip(1 + 0.3*tanh(pos - neg), 0.7, 1.3). Reuses
5253
- outcome_positive / outcome_negative; no schema
5254
- change. Default off. RESEARCH.md §PFC.vmPFC.
5255
- --rerank-utility OFC option-value re-ranker: combine relevance,
5256
- strength, and integration cost into a single utility
5257
- = score * (0.5 + 0.5 * strength) * (1 - cost_factor)
5258
- where cost_factor = min(0.3, tokens / 10000). Re-sorts
5259
- results by utility. Default off. RESEARCH.md §PFC.OFC.
5260
- --reranker <name> Apply a reranker pass after retrieval
5261
- (cross-encoder|llm). Looks up the named
5262
- reranker from src/rerankers/index.ts and re-orders
5263
- the top-K candidates. Default unset (no reranker).
5264
- See docs/plans/2026-05-10-f6-reranker-hardening.md.
5265
- --reranker-top-k <n> Cap candidates passed to the reranker (default 50).
5266
- --goal <tag> dlPFC goal-conditioned recall: memories tagged with
5267
- the goal tag get a 1.5x score boost and results are
5268
- re-sorted. Default off. RESEARCH.md §PFC.dlPFC.
5269
- --session-id <id> Session identifier for dlPFC goal-stack boost.
5270
- Defaults to \$HIPPO_SESSION_ID. When set and the
5271
- (tenant, session) has active goals (see
5272
- 'hippo goal push'), recall auto-boosts memories
5273
- whose tags match an active goal name. Boost stacks
5274
- on top of base BM25 score, capped at 3.0x.
5275
- --salience-threshold <n>
5276
- Pineal salience: down-weight memories whose
5277
- retrieval_count is below n. score *= max(0.5,
5278
- retrieval_count / n) for entries with count < n;
5279
- entries at or above n are unchanged. Salience emerges
5280
- from USE, not from lexical overlap. Default off.
5281
- RESEARCH.md §"AI Pineal Gland". (v1's creation-time
5282
- lexical gate destroyed LoCoMo 0.28 -> 0.02; this v2
5283
- is retrieval-side, opt-in only — see MEMORY.md
5284
- "Hippo salience gate destroys benchmark recall".)
5285
- --continuity Include continuity block (active task snapshot,
5286
- latest matching session handoff, last 5 session
5287
- events) above the memory list. Useful at agent
5288
- boot when you want both relevant memories AND
5289
- where you left off in one call. Anchored on the
5290
- active snapshot's session_id; no anchor = no
5291
- handoff/events (use 'hippo session resume' for
5292
- the explicit handoff-without-snapshot path).
5293
- explain <query> Show full score breakdown for each retrieved memory
5294
- --budget <n> Token budget (default: 4000)
5295
- --limit <n> Cap the number of results displayed
5296
- --json Output as JSON
5297
- --physics | --classic Force search mode (default: from config)
5298
- --no-mmr Disable MMR diversity re-ranking
5299
- --mmr-lambda <f> MMR balance 0..1 (default: 0.7, 1.0 = pure relevance)
5300
- trace <id> Memory dossier: content, decay trajectory, retrievals,
5301
- outcomes, consolidation parents, open conflicts
5302
- --json Output as JSON
5303
- refine Rewrite consolidated semantic memories with Claude
5304
- --limit <n> Cap the number of memories processed this run
5305
- --all Ignore \`llm-refined\` tag and re-refine everything
5306
- --dry-run Call the API but don't write results back
5307
- --model <id> Override the default model (claude-sonnet-4-6)
5308
- --json Output summary as JSON
5309
- (requires ANTHROPIC_API_KEY in env)
5310
- eval [<corpus.json>] Measure recall quality against a test corpus
5311
- --bootstrap Generate a synthetic corpus from current memories
5312
- --out <path> With --bootstrap, write to file instead of stdout
5313
- --max-cases <n> With --bootstrap, cap case count (default: 50)
5314
- --show-cases Print per-case details (query, R@10, missed, top 3)
5315
- --compare <path> JSON from a prior \`eval --json\` run; print deltas
5316
- --no-mmr Disable MMR for this eval run
5317
- --mmr-lambda <f> Override MMR lambda for this run
5318
- --embedding-weight <f> Override cosine weight (default: 0.6)
5319
- --local-bump <f> Local-over-global priority multiplier (default: 1.2)
5320
- --equal-sources Shortcut for --local-bump 1.0
5321
- --min-mrr <f> Exit non-zero if mean MRR falls below this
5322
- --json Output full summary as JSON
5323
- context Smart context injection for AI agents
5324
- --auto Auto-detect task from git state
5325
- --budget <n> Token budget (default: 1500)
5326
- --pinned-only Only inject pinned memories (used by UserPromptSubmit hook)
5327
- --include-recent <n> With --pinned-only, also inject the last N writes regardless of pinning
5328
- --format <fmt> Output format: markdown (default), json, or additional-context (Claude Code hook JSON)
5329
- --framing <mode> Framing: observe (default), suggest, assert
5330
- sleep Run consolidation pass (auto-learns + dedup + auto-shares)
5331
- --dry-run Preview without writing
5332
- --no-learn Skip auto git-learn before consolidation
5333
- --no-share Skip auto-sharing to global store
5334
- daily-runner Sweep registered workspaces and run daily learn+sleep
5335
- dedup Remove duplicate memories (keeps stronger copy)
5336
- --dry-run Preview without removing
5337
- --threshold <n> Overlap threshold 0-1 (default: 0.7)
5338
- status Show memory health stats
5339
- audit [--fix] Check memory quality (--fix removes junk)
5340
- github GitHub connector subcommands (backfill, dlq)
5341
- backfill --repo <owner/name> [--since ISO] [--max <N>]
5342
- Paginated backfill of issues + comments
5343
- dlq list List DLQ entries for the active tenant
5344
- dlq replay <id> [--force]
5345
- Re-ingest a DLQ entry (--force skips sig check)
5346
- provenance Provenance coverage gate for kind='raw' rows
5347
- --json Output as JSON
5348
- --strict Exit non-zero when coverage < 100%
5349
- drill <summary-id> Walk down a DAG level-2 summary to its children
5350
- --limit N Cap children list (default 50)
5351
- --budget N Cap total child token cost (≈ chars/4)
5352
- --json Output as JSON
5353
- assemble --session <id> Build a session's chronological context window
5354
- --budget N Token budget (default 4000)
5355
- --fresh-tail N Recent rows always kept verbatim (default 10)
5356
- --no-summarize-older Disable older-row summary substitution
5357
- --scope <s> Restrict to exact scope (default: deny *:private:*)
5358
- --json Output as JSON
5359
- correction-latency Wall-clock lag from receipt to supersession (p50/p95/max)
5360
- --json Output as JSON
5361
- outcome Apply feedback to last recall
5362
- --good Memories were helpful
5363
- --bad Memories were irrelevant
5364
- --id <id> Target a specific memory
5365
- conflicts List detected open memory conflicts
5366
- --status <status> Filter by status (default: open)
5367
- --json Output as JSON
5368
- resolve <conflict_id> Resolve a memory conflict
5369
- --keep <memory_id> Memory to keep (required)
5370
- --forget Delete the losing memory (default: halve half-life)
5371
- snapshot <sub> Persist or inspect the current active task
5372
- snapshot save Save active task state
5373
- --task <task>
5374
- --summary <summary>
5375
- --next-step <step>
5376
- --source <source> Optional source label
5377
- --session <id> Link snapshot to a session trail
5378
- snapshot show Show the active task snapshot
5379
- --json Output as JSON
5380
- snapshot clear Clear the active task snapshot
5381
- --status <status> Mark final status (default: cleared)
5382
- session <sub> Append or inspect short-term session history
5383
- session log Append a structured session event
5384
- --id <session-id>
5385
- --content <text>
5386
- --type <type> Event type (default: note)
5387
- --task <task> Optional task label
5388
- --source <source> Optional source label
5389
- session show Show recent events for a session or task
5390
- --id <session-id>
5391
- --task <task>
5392
- --limit <n> Event limit (default: 8)
5393
- --json Output as JSON
5394
- session latest Show latest task snapshot + events
5395
- --id <session-id> Filter by session
5396
- --json Output as JSON
5397
- session resume Re-inject latest handoff as context output
5398
- --id <session-id> Filter by session
5399
- handoff <sub> Manage session handoffs for continuity
5400
- handoff create Create a new session handoff
5401
- --summary <text> Handoff summary (required)
5402
- --next <text> Next action for successor
5403
- --session <id> Session ID (auto-generated if omitted)
5404
- --task <id> Associated task ID
5405
- --artifact <path> Related file path (repeatable)
5406
- handoff latest Show the most recent handoff
5407
- --session <id> Filter by session
5408
- --json Output as JSON
5409
- handoff show <id> Show a specific handoff by ID
5410
- current <sub> Show compact current state for agent injection
5411
- current show Active task + recent session events (default)
5412
- --json Output as JSON
5413
- forget <id> Force remove a memory
5414
- --archive Archive a raw (append-only) memory instead of deleting
5415
- --reason "<why>" Reason recorded on the archive (required with --archive)
5416
- inspect <id> Show full memory detail
5417
- embed Embed all memories for semantic search
5418
- --status Show embedding coverage
5419
- watch "<command>" Run command, auto-learn from failures
5420
- learn Learn lessons from repository history
5421
- --git Scan recent git commits for lessons
5422
- --days <n> Scan this many days back (default: 7)
5423
- --repos <paths> Comma-separated repo paths to scan
5424
- promote <id> Copy a local memory to the global store
5425
- share <id> Share a memory with attribution + transfer scoring
5426
- --force Share even if transfer score is low
5427
- --auto Auto-share all high-transfer-score memories
5428
- --dry-run Preview what would be shared
5429
- --min-score <n> Minimum transfer score (default: 0.6)
5430
- peers List projects contributing to global store
5431
- sync Pull global memories into local project
5432
- import Import memories from other AI tools
5433
- --chatgpt <path> Import from ChatGPT memory export (JSON or txt)
5434
- --claude <path> Import from CLAUDE.md or Claude memory.json
5435
- --cursor <path> Import from .cursorrules or .cursor/rules
5436
- --file <path> Import from any markdown or text file
5437
- --markdown <path> Import from structured MEMORY.md / AGENTS.md
5438
- --dry-run Preview without writing
5439
- --global Write to global store ($HIPPO_HOME or ~/.hippo/)
5440
- --tag <tag> Add extra tag (repeatable)
5441
- export [file] Export all memories (default: stdout)
5442
- --format <fmt> Output format: json (default) or markdown
5443
- capture Extract memories from conversation text
5444
- --stdin Read from piped input
5445
- --file <path> Read from a file
5446
- --last-session Read from the most recent agent session transcript
5447
- --transcript <path> Explicit transcript path (implies --last-session)
5448
- --log-file <path> Tee output to a log file (paired with 'hippo last-sleep')
5449
- --dry-run Preview without writing
5450
- --global Write to global store ($HIPPO_HOME or ~/.hippo/)
5451
- setup One-shot: detect installed AI tools and install all
5452
- available SessionEnd+SessionStart hooks
5453
- --all Install for every JSON-hook tool, even if not detected
5454
- --dry-run Show what would be installed without writing
5455
- --no-schedule Skip installing or repairing the daily runner
5456
- last-sleep Print the last 'hippo sleep --log-file' output and clear it
5457
- --path <p> Log path (default: ~/.hippo/logs/last-sleep.log)
5458
- --keep Print without clearing
5459
- codex-run [-- ...args] Launch real Codex behind Hippo's session-end wrapper
5460
- hook <sub> [target] Manage framework integrations
5461
- hook list Show available hooks
5462
- hook install <target> Install hook (claude-code|codex|cursor|openclaw|opencode|pi)
5463
- claude-code/opencode install SessionEnd+SessionStart;
5464
- codex wraps the detected launcher in place
5465
- hook uninstall <target> Remove hook
5466
- decide "<decision>" Record an architectural decision (90-day half-life)
5467
- --context "<why>" Why this decision was made
5468
- --supersedes <id> Supersede a previous decision (weakens it)
5469
- invalidate "<pattern>" Actively weaken memories matching an old pattern
5470
- --reason "<why>" Optional: what replaced it
5471
- wm <sub> Working memory bounded buffer for current state
5472
- wm push Push a working memory entry
5473
- --scope <scope> Scope name (default: default)
5474
- --content <text> Content to store (required)
5475
- --importance <n> Priority 0-1 (default: 0.5)
5476
- --session <id> Session ID
5477
- --task <id> Task ID
5478
- wm read Read working memory entries
5479
- --scope <scope> Filter by scope
5480
- --session <id> Filter by session
5481
- --limit <n> Max entries (default: 20)
5482
- --json Output as JSON
5483
- wm clear Clear working memory entries
5484
- --scope <scope> Filter by scope
5485
- --session <id> Filter by session
5486
- wm flush Flush working memory (session end)
5487
- --scope <scope> Filter by scope
5488
- --session <id> Filter by session
5489
- dashboard Open web dashboard for memory health
5490
- --port <n> Port to serve on (default: 3333)
5491
- mcp Start MCP server (stdio transport)
5492
- goal <sub> dlPFC goal stack (B3) — scoped per session
5493
- goal push <name> Push a new active goal; prints the new goal id
5494
- --policy <type> schema-fit-biased | error-prioritized |
5495
- recency-first | hybrid
5496
- --success "<cond>" Optional success condition text
5497
- --level <n> Goal level (default: 0)
5498
- --parent <goalId> Parent goal id (for sub-goals)
5499
- --session-id <s> Override session (defaults to HIPPO_SESSION_ID)
5500
- --tenant-id <t> Override tenant (defaults to HIPPO_TENANT)
5501
- goal list Show active goals as a table
5502
- --all Include suspended/completed goals
5503
- goal complete <id> Mark a goal completed
5504
- --outcome <0..1> Outcome score; >=0.7 boosts, <0.3 decays recalled mems
5505
- --no-propagate Close the goal without applying strength side-effects
5506
- goal suspend <id> Move an active goal to suspended
5507
- goal resume <id> Move a suspended goal back to active (depth-capped)
5508
- auth <sub> Manage API keys (A5 stub auth)
5509
- auth create Mint a new API key (plaintext shown ONCE)
5510
- --label <s> Optional human label
5511
- --role <r> admin | member (default: admin; member blocked from /v1/sleep)
5512
- --tenant <id> Override tenant (defaults to HIPPO_TENANT)
5513
- --json Output as JSON
5514
- --global Operate on the global store
5515
- auth list List API keys (active by default)
5516
- --all Include revoked keys
5517
- --json Output as JSON
5518
- --global Operate on the global store
5519
- auth revoke <key_id> Revoke an API key (subsequent validate fails)
5520
- --json Output as JSON
5521
- --global Operate on the global store
5522
- audit <sub> Query the append-only audit log (A5 stub auth)
5523
- audit list List audit events for the active tenant
5524
- --op <op> Filter by op (remember | recall | promote |
5525
- supersede | forget | archive_raw | auth_revoke)
5526
- --since <iso> Lower bound on ts (ISO timestamp)
5527
- --limit <n> Max events (default: 100, max: 10000)
5528
- --json Output as JSON
5529
- --global Operate on the global store
5530
-
5531
- Examples:
5532
- hippo init
5533
- hippo remember "FRED cache can silently drop series" --tag error
5534
- hippo recall "data pipeline issues" --budget 2000
5535
- hippo context --auto --budget 1500
5536
- hippo conflicts
5537
- hippo session log --id sess_123 --task "Ship feature" --type progress --content "Build is green, next step is docs"
5538
- hippo session latest --json
5539
- hippo session resume
5540
- hippo snapshot save --task "Ship feature" --summary "Tests are green" --next-step "Open the PR" --session sess_123
5541
- hippo handoff create --summary "PR is open, tests green" --next "Merge after review" --session sess_123 --artifact src/foo.ts
5542
- hippo embed --status
5543
- hippo watch "npm run build"
5544
- hippo learn --git --days 30
5545
- hippo promote mem_abc123
5546
- hippo sync
5547
- hippo setup
5548
- hippo hook install claude-code
5549
- hippo decide "Use PostgreSQL for new services" --context "JSONB support"
5550
- hippo invalidate "REST API" --reason "migrated to GraphQL"
5551
- hippo export memories.json
5552
- hippo export --format markdown memories.md
5553
- hippo sleep --dry-run
5554
- hippo outcome --good
5555
- hippo status
5416
+ console.log(`
5417
+ Hippo - biologically-inspired memory system for AI agents
5418
+
5419
+ Usage: hippo <command> [options]
5420
+
5421
+ Commands:
5422
+ init Create .hippo/ structure in current directory
5423
+ --scan [dir] Find all git repos under dir (default: ~) and init each
5424
+ --days <n> Days of git history to seed (default: 365 for --scan, 30 for single)
5425
+ --global Init the global store ($HIPPO_HOME or ~/.hippo/)
5426
+ --no-hooks Skip auto-detecting and installing agent hooks
5427
+ --no-schedule Skip auto-creating the machine-level daily runner
5428
+ --no-learn Skip seeding memories from git history
5429
+ remember <text> Store a memory
5430
+ --tag <tag> Add a tag (repeatable)
5431
+ --error Tag as error (boosts retention)
5432
+ --pin Pin memory (never decays)
5433
+ --verified Set confidence: verified (default)
5434
+ --observed Set confidence: observed
5435
+ --inferred Set confidence: inferred
5436
+ --global Store in global store ($HIPPO_HOME or ~/.hippo/)
5437
+ recall <query> Search and retrieve memories (local + global)
5438
+ --budget <n> Token budget (default: 4000)
5439
+ --min-results <n> Minimum results regardless of budget (default: 1)
5440
+ --json Output as JSON
5441
+ --why Show match reasons and source annotations
5442
+ --no-mmr Disable MMR diversity re-ranking
5443
+ --mmr-lambda <f> MMR balance 0..1 (default: 0.7, 1.0 = pure relevance)
5444
+ --evc-adaptive ACC-style: when top-K shows high inter-item overlap
5445
+ (= conflict cluster), expand pool and re-rank by
5446
+ recency. Default off. RESEARCH.md §PFC.ACC.
5447
+ --filter-conflicts vlPFC interference filter: drop superseded entries
5448
+ and 0.3x-downweight entries flagged in an open
5449
+ conflict with a peer in the same result set.
5450
+ Uses recorded supersession + conflicts only — never
5451
+ lexical inference. Default off. RESEARCH.md §PFC.vlPFC.
5452
+ --value-aware vmPFC value attribution: boost memories with positive
5453
+ cumulative outcomes and demote those with negative
5454
+ outcomes during ranking. Multiplier
5455
+ clip(1 + 0.3*tanh(pos - neg), 0.7, 1.3). Reuses
5456
+ outcome_positive / outcome_negative; no schema
5457
+ change. Default off. RESEARCH.md §PFC.vmPFC.
5458
+ --rerank-utility OFC option-value re-ranker: combine relevance,
5459
+ strength, and integration cost into a single utility
5460
+ = score * (0.5 + 0.5 * strength) * (1 - cost_factor)
5461
+ where cost_factor = min(0.3, tokens / 10000). Re-sorts
5462
+ results by utility. Default off. RESEARCH.md §PFC.OFC.
5463
+ --reranker <name> Apply a reranker pass after retrieval
5464
+ (cross-encoder|llm). Looks up the named
5465
+ reranker from src/rerankers/index.ts and re-orders
5466
+ the top-K candidates. Default unset (no reranker).
5467
+ See docs/plans/2026-05-10-f6-reranker-hardening.md.
5468
+ --reranker-top-k <n> Cap candidates passed to the reranker (default 50).
5469
+ --goal <tag> dlPFC goal-conditioned recall: memories tagged with
5470
+ the goal tag get a 1.5x score boost and results are
5471
+ re-sorted. Default off. RESEARCH.md §PFC.dlPFC.
5472
+ --session-id <id> Session identifier for dlPFC goal-stack boost.
5473
+ Defaults to \$HIPPO_SESSION_ID. When set and the
5474
+ (tenant, session) has active goals (see
5475
+ 'hippo goal push'), recall auto-boosts memories
5476
+ whose tags match an active goal name. Boost stacks
5477
+ on top of base BM25 score, capped at 3.0x.
5478
+ --salience-threshold <n>
5479
+ Pineal salience: down-weight memories whose
5480
+ retrieval_count is below n. score *= max(0.5,
5481
+ retrieval_count / n) for entries with count < n;
5482
+ entries at or above n are unchanged. Salience emerges
5483
+ from USE, not from lexical overlap. Default off.
5484
+ RESEARCH.md §"AI Pineal Gland". (v1's creation-time
5485
+ lexical gate destroyed LoCoMo 0.28 -> 0.02; this v2
5486
+ is retrieval-side, opt-in only — see MEMORY.md
5487
+ "Hippo salience gate destroys benchmark recall".)
5488
+ --continuity Include continuity block (active task snapshot,
5489
+ latest matching session handoff, last 5 session
5490
+ events) above the memory list. Useful at agent
5491
+ boot when you want both relevant memories AND
5492
+ where you left off in one call. Anchored on the
5493
+ active snapshot's session_id; no anchor = no
5494
+ handoff/events (use 'hippo session resume' for
5495
+ the explicit handoff-without-snapshot path).
5496
+ explain <query> Show full score breakdown for each retrieved memory
5497
+ --budget <n> Token budget (default: 4000)
5498
+ --limit <n> Cap the number of results displayed
5499
+ --json Output as JSON
5500
+ --physics | --classic Force search mode (default: from config)
5501
+ --no-mmr Disable MMR diversity re-ranking
5502
+ --mmr-lambda <f> MMR balance 0..1 (default: 0.7, 1.0 = pure relevance)
5503
+ trace <id> Memory dossier: content, decay trajectory, retrievals,
5504
+ outcomes, consolidation parents, open conflicts
5505
+ --json Output as JSON
5506
+ refine Rewrite consolidated semantic memories with Claude
5507
+ --limit <n> Cap the number of memories processed this run
5508
+ --all Ignore \`llm-refined\` tag and re-refine everything
5509
+ --dry-run Call the API but don't write results back
5510
+ --model <id> Override the default model (claude-sonnet-4-6)
5511
+ --json Output summary as JSON
5512
+ (requires ANTHROPIC_API_KEY in env)
5513
+ eval [<corpus.json>] Measure recall quality against a test corpus
5514
+ --bootstrap Generate a synthetic corpus from current memories
5515
+ --out <path> With --bootstrap, write to file instead of stdout
5516
+ --max-cases <n> With --bootstrap, cap case count (default: 50)
5517
+ --show-cases Print per-case details (query, R@10, missed, top 3)
5518
+ --compare <path> JSON from a prior \`eval --json\` run; print deltas
5519
+ --no-mmr Disable MMR for this eval run
5520
+ --mmr-lambda <f> Override MMR lambda for this run
5521
+ --embedding-weight <f> Override cosine weight (default: 0.6)
5522
+ --local-bump <f> Local-over-global priority multiplier (default: 1.2)
5523
+ --equal-sources Shortcut for --local-bump 1.0
5524
+ --min-mrr <f> Exit non-zero if mean MRR falls below this
5525
+ --json Output full summary as JSON
5526
+ context Smart context injection for AI agents
5527
+ --auto Auto-detect task from git state
5528
+ --budget <n> Token budget (default: 1500)
5529
+ --pinned-only Only inject pinned memories (used by UserPromptSubmit hook)
5530
+ --include-recent <n> With --pinned-only, also inject the last N writes regardless of pinning
5531
+ --format <fmt> Output format: markdown (default), json, or additional-context (Claude Code hook JSON)
5532
+ --framing <mode> Framing: observe (default), suggest, assert
5533
+ sleep Run consolidation pass (auto-learns + dedup + auto-shares)
5534
+ --dry-run Preview without writing
5535
+ --no-learn Skip auto git-learn before consolidation
5536
+ --no-share Skip auto-sharing to global store
5537
+ daily-runner Sweep registered workspaces and run daily learn+sleep
5538
+ dedup Remove duplicate memories (keeps stronger copy)
5539
+ --dry-run Preview without removing
5540
+ --threshold <n> Overlap threshold 0-1 (default: 0.7)
5541
+ status Show memory health stats
5542
+ audit [--fix] Check memory quality (--fix removes junk)
5543
+ github GitHub connector subcommands (backfill, dlq)
5544
+ backfill --repo <owner/name> [--since ISO] [--max <N>]
5545
+ Paginated backfill of issues + comments
5546
+ dlq list List DLQ entries for the active tenant
5547
+ dlq replay <id> [--force]
5548
+ Re-ingest a DLQ entry (--force skips sig check)
5549
+ provenance Provenance coverage gate for kind='raw' rows
5550
+ --json Output as JSON
5551
+ --strict Exit non-zero when coverage < 100%
5552
+ drill <summary-id> Walk down a DAG level-2 summary to its children
5553
+ --limit N Cap children list (default 50)
5554
+ --budget N Cap total child token cost (≈ chars/4)
5555
+ --json Output as JSON
5556
+ assemble --session <id> Build a session's chronological context window
5557
+ --budget N Token budget (default 4000)
5558
+ --fresh-tail N Recent rows always kept verbatim (default 10)
5559
+ --no-summarize-older Disable older-row summary substitution
5560
+ --scope <s> Restrict to exact scope (default: deny *:private:*)
5561
+ --json Output as JSON
5562
+ correction-latency Wall-clock lag from receipt to supersession (p50/p95/max)
5563
+ --json Output as JSON
5564
+ outcome Apply feedback to last recall
5565
+ --good Memories were helpful
5566
+ --bad Memories were irrelevant
5567
+ --id <id> Target a specific memory
5568
+ conflicts List detected open memory conflicts
5569
+ --status <status> Filter by status (default: open)
5570
+ --json Output as JSON
5571
+ resolve <conflict_id> Resolve a memory conflict
5572
+ --keep <memory_id> Memory to keep (required)
5573
+ --forget Delete the losing memory (default: halve half-life)
5574
+ snapshot <sub> Persist or inspect the current active task
5575
+ snapshot save Save active task state
5576
+ --task <task>
5577
+ --summary <summary>
5578
+ --next-step <step>
5579
+ --source <source> Optional source label
5580
+ --session <id> Link snapshot to a session trail
5581
+ snapshot show Show the active task snapshot
5582
+ --json Output as JSON
5583
+ snapshot clear Clear the active task snapshot
5584
+ --status <status> Mark final status (default: cleared)
5585
+ session <sub> Append or inspect short-term session history
5586
+ session log Append a structured session event
5587
+ --id <session-id>
5588
+ --content <text>
5589
+ --type <type> Event type (default: note)
5590
+ --task <task> Optional task label
5591
+ --source <source> Optional source label
5592
+ session show Show recent events for a session or task
5593
+ --id <session-id>
5594
+ --task <task>
5595
+ --limit <n> Event limit (default: 8)
5596
+ --json Output as JSON
5597
+ session latest Show latest task snapshot + events
5598
+ --id <session-id> Filter by session
5599
+ --json Output as JSON
5600
+ session resume Re-inject latest handoff as context output
5601
+ --id <session-id> Filter by session
5602
+ handoff <sub> Manage session handoffs for continuity
5603
+ handoff create Create a new session handoff
5604
+ --summary <text> Handoff summary (required)
5605
+ --next <text> Next action for successor
5606
+ --session <id> Session ID (auto-generated if omitted)
5607
+ --task <id> Associated task ID
5608
+ --artifact <path> Related file path (repeatable)
5609
+ handoff latest Show the most recent handoff
5610
+ --session <id> Filter by session
5611
+ --json Output as JSON
5612
+ handoff show <id> Show a specific handoff by ID
5613
+ current <sub> Show compact current state for agent injection
5614
+ current show Active task + recent session events (default)
5615
+ --json Output as JSON
5616
+ forget <id> Force remove a memory
5617
+ --archive Archive a raw (append-only) memory instead of deleting
5618
+ --reason "<why>" Reason recorded on the archive (required with --archive)
5619
+ inspect <id> Show full memory detail
5620
+ embed Embed all memories for semantic search
5621
+ --status Show embedding coverage
5622
+ watch "<command>" Run command, auto-learn from failures
5623
+ learn Learn lessons from repository history
5624
+ --git Scan recent git commits for lessons
5625
+ --days <n> Scan this many days back (default: 7)
5626
+ --repos <paths> Comma-separated repo paths to scan
5627
+ promote <id> Copy a local memory to the global store
5628
+ share <id> Share a memory with attribution + transfer scoring
5629
+ --force Share even if transfer score is low
5630
+ --auto Auto-share all high-transfer-score memories
5631
+ --dry-run Preview what would be shared
5632
+ --min-score <n> Minimum transfer score (default: 0.6)
5633
+ peers List projects contributing to global store
5634
+ sync Pull global memories into local project
5635
+ import Import memories from other AI tools
5636
+ --chatgpt <path> Import from ChatGPT memory export (JSON or txt)
5637
+ --claude <path> Import from CLAUDE.md or Claude memory.json
5638
+ --cursor <path> Import from .cursorrules or .cursor/rules
5639
+ --file <path> Import from any markdown or text file
5640
+ --markdown <path> Import from structured MEMORY.md / AGENTS.md
5641
+ --dry-run Preview without writing
5642
+ --global Write to global store ($HIPPO_HOME or ~/.hippo/)
5643
+ --tag <tag> Add extra tag (repeatable)
5644
+ export [file] Export all memories (default: stdout)
5645
+ --format <fmt> Output format: json (default) or markdown
5646
+ capture Extract memories from conversation text
5647
+ --stdin Read from piped input
5648
+ --file <path> Read from a file
5649
+ --last-session Read from the most recent agent session transcript
5650
+ --transcript <path> Explicit transcript path (implies --last-session)
5651
+ --log-file <path> Tee output to a log file (paired with 'hippo last-sleep')
5652
+ --dry-run Preview without writing
5653
+ --global Write to global store ($HIPPO_HOME or ~/.hippo/)
5654
+ setup One-shot: detect installed AI tools and install all
5655
+ available SessionEnd+SessionStart hooks
5656
+ --all Install for every JSON-hook tool, even if not detected
5657
+ --dry-run Show what would be installed without writing
5658
+ --no-schedule Skip installing or repairing the daily runner
5659
+ last-sleep Print the last 'hippo sleep --log-file' output and clear it
5660
+ --path <p> Log path (default: ~/.hippo/logs/last-sleep.log)
5661
+ --keep Print without clearing
5662
+ codex-run [-- ...args] Launch real Codex behind Hippo's session-end wrapper
5663
+ hook <sub> [target] Manage framework integrations
5664
+ hook list Show available hooks
5665
+ hook install <target> Install hook (claude-code|codex|cursor|openclaw|opencode|pi)
5666
+ claude-code/opencode install SessionEnd+SessionStart;
5667
+ codex wraps the detected launcher in place
5668
+ hook uninstall <target> Remove hook
5669
+ decide "<decision>" Record a decision (first-class object + memory mirror)
5670
+ --context "<why>" Why this decision was made
5671
+ --supersedes <mem-id> Supersede the decision backed by this memory id
5672
+ decide list [--status active|superseded|closed|all] [--limit N]
5673
+ List decisions (table is authoritative, survives decay)
5674
+ decide get <id> Show a decision by its table id
5675
+ decide close <id> Retire (close) an active decision by its table id
5676
+ invalidate "<pattern>" Actively weaken memories matching an old pattern
5677
+ --reason "<why>" Optional: what replaced it
5678
+ wm <sub> Working memory bounded buffer for current state
5679
+ wm push Push a working memory entry
5680
+ --scope <scope> Scope name (default: default)
5681
+ --content <text> Content to store (required)
5682
+ --importance <n> Priority 0-1 (default: 0.5)
5683
+ --session <id> Session ID
5684
+ --task <id> Task ID
5685
+ wm read Read working memory entries
5686
+ --scope <scope> Filter by scope
5687
+ --session <id> Filter by session
5688
+ --limit <n> Max entries (default: 20)
5689
+ --json Output as JSON
5690
+ wm clear Clear working memory entries
5691
+ --scope <scope> Filter by scope
5692
+ --session <id> Filter by session
5693
+ wm flush Flush working memory (session end)
5694
+ --scope <scope> Filter by scope
5695
+ --session <id> Filter by session
5696
+ dashboard Open web dashboard for memory health
5697
+ --port <n> Port to serve on (default: 3333)
5698
+ mcp Start MCP server (stdio transport)
5699
+ goal <sub> dlPFC goal stack (B3) — scoped per session
5700
+ goal push <name> Push a new active goal; prints the new goal id
5701
+ --policy <type> schema-fit-biased | error-prioritized |
5702
+ recency-first | hybrid
5703
+ --success "<cond>" Optional success condition text
5704
+ --level <n> Goal level (default: 0)
5705
+ --parent <goalId> Parent goal id (for sub-goals)
5706
+ --session-id <s> Override session (defaults to HIPPO_SESSION_ID)
5707
+ --tenant-id <t> Override tenant (defaults to HIPPO_TENANT)
5708
+ goal list Show active goals as a table
5709
+ --all Include suspended/completed goals
5710
+ goal complete <id> Mark a goal completed
5711
+ --outcome <0..1> Outcome score; >=0.7 boosts, <0.3 decays recalled mems
5712
+ --no-propagate Close the goal without applying strength side-effects
5713
+ goal suspend <id> Move an active goal to suspended
5714
+ goal resume <id> Move a suspended goal back to active (depth-capped)
5715
+ auth <sub> Manage API keys (A5 stub auth)
5716
+ auth create Mint a new API key (plaintext shown ONCE)
5717
+ --label <s> Optional human label
5718
+ --role <r> admin | member (default: admin; member blocked from /v1/sleep)
5719
+ --tenant <id> Override tenant (defaults to HIPPO_TENANT)
5720
+ --json Output as JSON
5721
+ --global Operate on the global store
5722
+ auth list List API keys (active by default)
5723
+ --all Include revoked keys
5724
+ --json Output as JSON
5725
+ --global Operate on the global store
5726
+ auth revoke <key_id> Revoke an API key (subsequent validate fails)
5727
+ --json Output as JSON
5728
+ --global Operate on the global store
5729
+ audit <sub> Query the append-only audit log (A5 stub auth)
5730
+ audit list List audit events for the active tenant
5731
+ --op <op> Filter by op (remember | recall | promote |
5732
+ supersede | forget | archive_raw | auth_revoke)
5733
+ --since <iso> Lower bound on ts (ISO timestamp)
5734
+ --limit <n> Max events (default: 100, max: 10000)
5735
+ --json Output as JSON
5736
+ --global Operate on the global store
5737
+
5738
+ Examples:
5739
+ hippo init
5740
+ hippo remember "FRED cache can silently drop series" --tag error
5741
+ hippo recall "data pipeline issues" --budget 2000
5742
+ hippo context --auto --budget 1500
5743
+ hippo conflicts
5744
+ hippo session log --id sess_123 --task "Ship feature" --type progress --content "Build is green, next step is docs"
5745
+ hippo session latest --json
5746
+ hippo session resume
5747
+ hippo snapshot save --task "Ship feature" --summary "Tests are green" --next-step "Open the PR" --session sess_123
5748
+ hippo handoff create --summary "PR is open, tests green" --next "Merge after review" --session sess_123 --artifact src/foo.ts
5749
+ hippo embed --status
5750
+ hippo watch "npm run build"
5751
+ hippo learn --git --days 30
5752
+ hippo promote mem_abc123
5753
+ hippo sync
5754
+ hippo setup
5755
+ hippo hook install claude-code
5756
+ hippo decide "Use PostgreSQL for new services" --context "JSONB support"
5757
+ hippo invalidate "REST API" --reason "migrated to GraphQL"
5758
+ hippo export memories.json
5759
+ hippo export --format markdown memories.md
5760
+ hippo sleep --dry-run
5761
+ hippo outcome --good
5762
+ hippo status
5556
5763
  `);
5557
5764
  }
5558
5765
  // ---------------------------------------------------------------------------
@@ -6150,52 +6357,9 @@ async function main() {
6150
6357
  }
6151
6358
  break;
6152
6359
  }
6153
- case 'decide': {
6154
- requireInit(hippoRoot);
6155
- const text = args[0];
6156
- if (!text) {
6157
- console.error('Usage: hippo decide "<decision>" [--context "<why>"] [--supersedes <id>]');
6158
- process.exit(1);
6159
- }
6160
- const context = flags['context'] || '';
6161
- const supersedesId = flags['supersedes'] || null;
6162
- // Build content with context
6163
- const decisionContent = context ? `${text}\n\nContext: ${context}` : text;
6164
- // Handle supersession
6165
- if (supersedesId) {
6166
- const oldEntry = readEntry(hippoRoot, supersedesId, resolveTenantId({}));
6167
- if (!oldEntry) {
6168
- console.error(`Memory ${supersedesId} not found.`);
6169
- process.exit(1);
6170
- }
6171
- oldEntry.half_life_days = Math.max(1, Math.floor(oldEntry.half_life_days / 2));
6172
- oldEntry.confidence = 'stale';
6173
- if (!oldEntry.tags.includes('superseded'))
6174
- oldEntry.tags.push('superseded');
6175
- writeEntry(hippoRoot, oldEntry);
6176
- console.log(`Superseded ${supersedesId} (half-life halved, marked stale)`);
6177
- }
6178
- // Create decision memory
6179
- const mem = createMemory(decisionContent, {
6180
- tags: ['decision'],
6181
- layer: Layer.Semantic,
6182
- confidence: 'verified',
6183
- source: 'decision',
6184
- });
6185
- mem.half_life_days = DECISION_HALF_LIFE_DAYS;
6186
- // Auto-tag with path context
6187
- const decisionPathTags = extractPathTags(process.cwd());
6188
- for (const pt of decisionPathTags) {
6189
- if (!mem.tags.includes(pt))
6190
- mem.tags.push(pt);
6191
- }
6192
- writeEntry(hippoRoot, mem);
6193
- console.log(`Decision recorded: ${mem.id}`);
6194
- if (supersedesId) {
6195
- console.log(` Supersedes: ${supersedesId}`);
6196
- }
6360
+ case 'decide':
6361
+ cmdDecide(hippoRoot, args, flags);
6197
6362
  break;
6198
- }
6199
6363
  case 'help':
6200
6364
  case '--help':
6201
6365
  case '-h':