@gamaze/hicortex 0.20.0 → 0.20.1

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.
@@ -293,11 +293,16 @@ function parseJsonLenient(text, fallback) {
293
293
  // ---------------------------------------------------------------------------
294
294
  // Stage 1: Pre-check
295
295
  // ---------------------------------------------------------------------------
296
- function readLastConsolidated() {
297
- return (0, state_js_1.loadState)().lastConsolidated ?? "";
296
+ function readLastConsolidated(stateDir) {
297
+ // stateDir-optional for backcompat; runConsolidation threads its own
298
+ // stateDir so the skip decision reads the SAME state the run writes
299
+ // (previously this read the ambient home — a split-brain where a test or
300
+ // CLI caller with an isolated stateDir decided "skip" from the operator's
301
+ // real ~/.hicortex watermark).
302
+ return (0, state_js_1.loadState)(stateDir).lastConsolidated ?? "";
298
303
  }
299
- function stagePrecheck(db) {
300
- const lastTs = readLastConsolidated();
304
+ function stagePrecheck(db, stateDir) {
305
+ const lastTs = readLastConsolidated(stateDir);
301
306
  const lastDt = lastTs || "1970-01-01T00:00:00.000Z";
302
307
  const newMemories = storage.getMemoriesSince(db, lastDt);
303
308
  if (newMemories.length === 0) {
@@ -1372,7 +1377,7 @@ memorySoftCap) {
1372
1377
  stages: {},
1373
1378
  };
1374
1379
  // Stage 1: Pre-check
1375
- const precheck = stagePrecheck(db);
1380
+ const precheck = stagePrecheck(db, stateDir);
1376
1381
  // Also check for unscored memories
1377
1382
  const unscored = storage.getUnscoredMemories(db);
1378
1383
  const newIds = new Set(precheck.newMemories.map((m) => m.id));
@@ -1380,7 +1385,15 @@ memorySoftCap) {
1380
1385
  ...precheck.newMemories,
1381
1386
  ...unscored.filter((m) => !newIds.has(m.id)),
1382
1387
  ];
1383
- const skip = scoreMemories.length === 0;
1388
+ // #194 no-fit scope: untagged rows (domain IS NULL) stay in the
1389
+ // re-evaluation scope — the decay/re-attempt contract ("re-halves once per
1390
+ // run while still below the floor") is work even on a quiet night with
1391
+ // nothing new. The skip below gated on new+unscored only, which the tests
1392
+ // never caught because stagePrecheck used to read the AMBIENT (always
1393
+ // empty in the suite) state instead of the run's own watermark — threading
1394
+ // stateDir (#357) exposed the divergence between test and production.
1395
+ const nofitInScope = db.prepare("SELECT COUNT(*) AS n FROM memories WHERE domain IS NULL").get().n;
1396
+ const skip = scoreMemories.length === 0 && nofitInScope === 0;
1384
1397
  report.stages.precheck = {
1385
1398
  skip,
1386
1399
  reason: skip
@@ -1450,8 +1463,18 @@ memorySoftCap) {
1450
1463
  report.status = "failed";
1451
1464
  console.error("[hicortex] Consolidation pipeline error:", err);
1452
1465
  }
1453
- // Update last-consolidated timestamp
1454
- if (!dryRun && report.status === "completed") {
1466
+ // Update last-consolidated timestamp. #357: the stages fail SOFT, so a run
1467
+ // against an endpoint that died mid-way still reports status "completed"
1468
+ // here — advancing the timestamp made state.json disagree with the
1469
+ // nightly's breaker-open override to endpoint_down (observed 0.20.0 soak:
1470
+ // endpoint_down reported, lastConsolidated advanced anyway). Gate on the
1471
+ // SAME signal the nightly's override reads (llm.breakerOpen) so the two
1472
+ // sites agree for the breaker case — keep this condition and the override
1473
+ // in nightly.ts in sync if either ever grows. (Sibling soft-fail paths —
1474
+ // e.g. a sustained-429 run, which never accrues to the breaker because a
1475
+ // 429 proves the endpoint answers — still advance; that is the #337
1476
+ // taxonomy working as designed.)
1477
+ if (!dryRun && report.status === "completed" && !llm.breakerOpen) {
1455
1478
  (0, state_js_1.updateState)((s) => {
1456
1479
  s.lastConsolidated = new Date().toISOString();
1457
1480
  return s;
package/dist/init.d.ts CHANGED
@@ -25,6 +25,13 @@ import type { DomainDef } from "./types.js";
25
25
  * - "registered" — listed but connection not confirmed (server down / not restarted)
26
26
  */
27
27
  export declare function parseMcpListStatus(mcpListOutput: string): "connected" | "registered" | "missing";
28
+ /**
29
+ * The client config's serverUrl BEFORE this run re-points it — the value init
30
+ * last wrote into the Hermes plugin's config (so the plugin step can tell an
31
+ * init-owned URL from a user-set one). Exported for tests.
32
+ */
33
+ export declare function readPreviousServerUrl(configPath: string): string | undefined;
34
+ export declare function setupHermes(serverUrl: string, authToken: string, previousServerUrl?: string): void;
28
35
  /**
29
36
  * Parse a KEY=VALUE env file (e.g. ~/.hermes/.env or ~/.claude/settings.json env block).
30
37
  * Handles: comments (#), quoted values, empty lines.
package/dist/init.js CHANGED
@@ -21,6 +21,8 @@
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
22
  exports.GENERIC_DEFAULT_DOMAINS = void 0;
23
23
  exports.parseMcpListStatus = parseMcpListStatus;
24
+ exports.readPreviousServerUrl = readPreviousServerUrl;
25
+ exports.setupHermes = setupHermes;
24
26
  exports.parseEnvFile = parseEnvFile;
25
27
  exports.isLlmConfigured = isLlmConfigured;
26
28
  exports.persistLlmConfig = persistLlmConfig;
@@ -399,7 +401,21 @@ function setupOpencode() {
399
401
  // ---------------------------------------------------------------------------
400
402
  // Hermes setup
401
403
  // ---------------------------------------------------------------------------
402
- function setupHermes(serverUrl, authToken) {
404
+ /**
405
+ * The client config's serverUrl BEFORE this run re-points it — the value init
406
+ * last wrote into the Hermes plugin's config (so the plugin step can tell an
407
+ * init-owned URL from a user-set one). Exported for tests.
408
+ */
409
+ function readPreviousServerUrl(configPath) {
410
+ try {
411
+ const { config: prev } = loadConfigStrict(configPath);
412
+ if (typeof prev.serverUrl === "string" && prev.serverUrl)
413
+ return prev.serverUrl;
414
+ }
415
+ catch { /* no prior config, or unreadable — nothing init-owned to carry */ }
416
+ return undefined;
417
+ }
418
+ function setupHermes(serverUrl, authToken, previousServerUrl) {
403
419
  const pluginSource = (0, node_path_1.join)(__dirname, "..", "hermes-plugin", "hicortex");
404
420
  if (!(0, node_fs_1.existsSync)(pluginSource)) {
405
421
  console.log(" ⚠ Hermes plugin not found in package — skipping Hermes setup");
@@ -407,23 +423,86 @@ function setupHermes(serverUrl, authToken) {
407
423
  }
408
424
  const pluginsDir = (0, node_path_1.join)(HERMES_HOME, "plugins", "hicortex");
409
425
  (0, node_fs_1.mkdirSync)(pluginsDir, { recursive: true });
410
- // Copy plugin files
411
- const pluginFiles = (0, node_fs_1.readdirSync)(pluginSource);
412
- for (const f of pluginFiles) {
413
- const src = (0, node_path_1.join)(pluginSource, f);
414
- if ((0, node_fs_1.statSync)(src).isFile()) {
415
- (0, node_fs_1.copyFileSync)(src, (0, node_path_1.join)(pluginsDir, f));
416
- }
426
+ // If the plugin was installed via `hermes plugins install` (a git checkout
427
+ // that actually contains the plugin — .git alone could be an empty/partial
428
+ // dir), do NOT copy over it — that would mix a managed checkout with
429
+ // copied files and break its own update path. The config below is still
430
+ // written: Hermes' own `memory setup` writes config.json into that tree
431
+ // too, so the file is expected there regardless of install path.
432
+ const isGitInstall = (0, node_fs_1.existsSync)((0, node_path_1.join)(pluginsDir, ".git")) && (0, node_fs_1.existsSync)((0, node_path_1.join)(pluginsDir, "plugin.yaml"));
433
+ if (isGitInstall) {
434
+ console.log(" ✓ Hermes plugin already installed (git checkout) — leaving its files, updating config only");
417
435
  }
418
- console.log(` ✓ Copied Hermes plugin to ${pluginsDir}`);
419
- // Write plugin config.json (server URL only). The auth token is a SECRET and
420
- // is deliberately NOT written here — `hermes memory setup` routes it to
421
- // $HERMES_HOME/.env, and localhost bypasses auth entirely. Capture threshold
422
- // omitted the plugin's own default applies.
423
- const config = { hicortex_url: serverUrl };
436
+ else {
437
+ const pluginFiles = (0, node_fs_1.readdirSync)(pluginSource);
438
+ for (const f of pluginFiles) {
439
+ // NEVER copy a bundled config.json over the user's: a stray one in a
440
+ // developer tree ships via prepack, and clobbering here would defeat
441
+ // the merge logic below (it runs AFTER this loop).
442
+ if (f === "config.json")
443
+ continue;
444
+ const src = (0, node_path_1.join)(pluginSource, f);
445
+ if ((0, node_fs_1.statSync)(src).isFile()) {
446
+ (0, node_fs_1.copyFileSync)(src, (0, node_path_1.join)(pluginsDir, f));
447
+ }
448
+ }
449
+ console.log(` ✓ Copied Hermes plugin to ${pluginsDir}`);
450
+ }
451
+ // Plugin config.json: MERGE, never blindly clobber. The URL is overwritten
452
+ // when it is INIT-OWNED — unset, a local default (either host spelling:
453
+ // init has written both `localhost` and `127.0.0.1` variants historically),
454
+ // or exactly what init last wrote (previousServerUrl — the client config's
455
+ // serverUrl BEFORE this run re-pointed it). A value the USER set by hand to
456
+ // something else is preserved WITH A LOUD DIVERGENCE WARNING — silently
457
+ // keeping a stale endpoint on a re-point is the failure this guards
458
+ // (CR: re-point must reach the plugin like it reaches CC's MCP entry).
459
+ // The auth token is a SECRET and is deliberately NOT written here —
460
+ // `hermes memory setup` routes it to $HERMES_HOME/.env, and localhost
461
+ // bypasses auth entirely.
462
+ const stripTrailingSlash = (v) => v.replace(/\/+$/, "");
463
+ const localDefaults = [`http://localhost:${DEFAULT_PORT}`, `http://127.0.0.1:${DEFAULT_PORT}`];
464
+ // Normalize before comparing (trailing-slash variants of the same URL must
465
+ // not read as user-set — the client flow strips, the env-var flow does not).
466
+ const normalizedPrevious = previousServerUrl ? stripTrailingSlash(previousServerUrl) : undefined;
467
+ const isInitOwnedUrl = (v) => {
468
+ if (typeof v !== "string" || v === "")
469
+ return true;
470
+ const nv = stripTrailingSlash(v);
471
+ return localDefaults.includes(nv) || nv === normalizedPrevious;
472
+ };
424
473
  const configPath = (0, node_path_1.join)(pluginsDir, "config.json");
425
- (0, node_fs_1.writeFileSync)(configPath, JSON.stringify(config, null, 2));
426
- console.log(` ✓ Plugin config → ${serverUrl}`);
474
+ let config = {};
475
+ if ((0, node_fs_1.existsSync)(configPath)) {
476
+ try {
477
+ config = loadConfigStrict(configPath).config;
478
+ }
479
+ catch {
480
+ // Corrupt/unreadable plugin config: REPLACE (this file holds no secrets
481
+ // by design — only URL/knobs; reset to defaults) — loudly, never
482
+ // silently, never fatally. (The underlying error's copy speaks of
483
+ // ~/.hicortex config semantics that do not apply to this file, so it
484
+ // is deliberately not echoed.)
485
+ console.log(" ⚠ Plugin config.json unreadable — replacing it (URL re-prefilled; optional knobs reset to defaults; no secrets live in this file)");
486
+ config = {};
487
+ }
488
+ }
489
+ const normalizedServerUrl = stripTrailingSlash(serverUrl);
490
+ let keptExistingUrl = false;
491
+ if (isInitOwnedUrl(config.hicortex_url)) {
492
+ config.hicortex_url = normalizedServerUrl;
493
+ }
494
+ else if (stripTrailingSlash(config.hicortex_url) !== normalizedServerUrl) {
495
+ keptExistingUrl = true;
496
+ console.log(` ℹ Kept existing plugin URL ${config.hicortex_url} (differs from this install's ${normalizedServerUrl})`);
497
+ console.log(" Edit ~/.hermes/plugins/hicortex/config.json if that is not what you want.");
498
+ }
499
+ try {
500
+ (0, node_fs_1.writeFileSync)(configPath, JSON.stringify(config, null, 2));
501
+ console.log(keptExistingUrl ? ` ℹ Plugin config stays on ${config.hicortex_url}` : ` ✓ Plugin config → ${config.hicortex_url}`);
502
+ }
503
+ catch (e) {
504
+ console.log(` ⚠ Could not write plugin config (${e instanceof Error ? e.message : e}) — Hermes setup skipped config pre-fill`);
505
+ }
427
506
  // For profile-based setups, symlink the shared plugin into each profile's
428
507
  // plugin dir (non-destructive). Discovery scans $HERMES_HOME/plugins/, so
429
508
  // this is belt-and-suspenders for profile-scoped installs.
@@ -460,14 +539,26 @@ function setupHermes(serverUrl, authToken) {
460
539
  // Activation is left to Hermes' own tooling. We NEVER edit config.yaml —
461
540
  // Hermes' `memory setup` discovers this plugin automatically and writes the
462
541
  // config with its own YAML-aware writer (routing the token to .env).
463
- const isRemote = !(serverUrl.includes("127.0.0.1") || serverUrl.includes("localhost"));
464
- console.log(" → Activate with: hermes memory setup (select 'hicortex')");
542
+ // The token is PRINTED here for the remote case (the user's own terminal —
543
+ // same visibility as `hicortex status`); Hermes has no non-interactive
544
+ // setup path, so one paste is the floor. When a user-set URL was KEPT, the
545
+ // token hint names that server's token requirement instead (this install's
546
+ // token belongs to a different server).
547
+ console.log(" → Activate with: hermes memory setup hicortex");
465
548
  if ((0, node_fs_1.existsSync)(profilesDir)) {
466
549
  console.log(" Run once per profile if you use Hermes profiles.");
467
550
  }
468
- if (isRemote) {
469
- console.log(" Remote server: enter the auth token when prompted (stored in $HERMES_HOME/.env).");
551
+ if (keptExistingUrl) {
552
+ console.log(" The kept URL's server needs ITS token run `hicortex status` on that machine if you don't have it.");
553
+ }
554
+ else if (authToken) {
555
+ console.log(` When prompted for the token, paste: ${authToken}`);
556
+ console.log(" (stored by Hermes in $HERMES_HOME/.env — never in the plugin's config.json)");
557
+ }
558
+ else {
559
+ console.log(" Local server: leave the token blank — localhost bypasses auth.");
470
560
  }
561
+ console.log(" Installed Hermes AFTER Hicortex? Re-running `npx @gamaze/hicortex init` redoes this step.");
471
562
  }
472
563
  /**
473
564
  * Parse a KEY=VALUE env file (e.g. ~/.hermes/.env or ~/.claude/settings.json env block).
@@ -1850,6 +1941,11 @@ async function runClientInit(serverUrl, agentName) {
1850
1941
  // writeClientConfig: strict-load → apply overrides → save. Throws on a
1851
1942
  // malformed existing config (0.16.x BLOCKER — never wipe the client's
1852
1943
  // authToken/licenseKey). ENOENT → fresh client config.
1944
+ // The PRE-overwrite serverUrl is captured first: it is what init last
1945
+ // wrote into the Hermes plugin's config, so the plugin step can tell an
1946
+ // init-owned URL (update it — re-point must reach Hermes like it reaches
1947
+ // CC's MCP entry) from a user-set one (keep + warn).
1948
+ const previousServerUrl = readPreviousServerUrl(configPath);
1853
1949
  const { config } = writeClientConfig(configPath, { serverUrl, authToken }, nameDecision);
1854
1950
  console.log(` ✓ Client config saved to ${configPath}`);
1855
1951
  if (typeof config.agentName === "string") {
@@ -1906,7 +2002,7 @@ async function runClientInit(serverUrl, agentName) {
1906
2002
  // Step 8: Setup Hermes if detected
1907
2003
  if ((0, node_fs_1.existsSync)(HERMES_HOME)) {
1908
2004
  console.log("\nHermes detected — installing plugin...");
1909
- setupHermes(serverUrl, authToken);
2005
+ setupHermes(serverUrl, authToken, previousServerUrl);
1910
2006
  }
1911
2007
  // Step 8b: Setup the Pi extension if detected (self-resolving — no config write)
1912
2008
  if ((0, node_fs_1.existsSync)(PI_AGENT_DIR)) {
package/dist/nightly.js CHANGED
@@ -741,8 +741,11 @@ async function runNightly(options = {}) {
741
741
  consolidationStatus = report.status;
742
742
  // #337: the stages fail soft, so a run against an endpoint that died
743
743
  // MID-run would otherwise report "completed". An open breaker is the
744
- // honest signal — override to endpoint_down (lastConsolidated still
745
- // only advances on a clean "completed", so the work is re-run).
744
+ // honest signal — override to endpoint_down. lastConsolidated only
745
+ // advances on a clean completed AND a closed breaker (the same
746
+ // llm.breakerOpen signal, gated in consolidate.ts — keep the two
747
+ // sites in lockstep), so the importance/reflection/domain work is
748
+ // re-run on the next pass.
746
749
  if (llm.breakerOpen) {
747
750
  console.error(`[hicortex] LLM circuit breaker OPEN after consolidation — ` +
748
751
  `overriding "${report.status}" to endpoint_down (stages failed ` +
@@ -78,7 +78,7 @@ hermes memory setup # select "hicortex", enter the server URL/token when promp
78
78
 
79
79
  Run it once per profile if you use Hermes profiles. Hermes allows **one** external memory provider at a time, so disable Honcho (or any other) first, then restart the gateway.
80
80
 
81
- Config fields (`hicortex_url`, `default_project`, `recall_limit`, `privacy_filter`, `agent_name`) can also be written to `$HERMES_HOME/plugins/hicortex/config.json` directly. `agent_name` pins the per-agent context id for this profile (leave blank to auto-derive — see [Per-agent standing context](#per-agent-standing-context-013)). The auth token is a **secret** — set it via env, not the JSON file:
81
+ Setup asks exactly two questions: the **server URL** and the **auth token**. Everything else has a correct default and is configured — if ever needed — directly in `$HERMES_HOME/plugins/hicortex/config.json`: `default_project` (blank = memories unattributed), `recall_limit` (default 5; sizes the tools and the legacy `/search` fallback only — the pushed recall index is sized by SERVER config `recallMaxItems`), `agent_name` (blank auto-derives from the running profile; pin it only for fleet re-installs — see [Per-agent standing context](#per-agent-standing-context-013)), and `mission_domains` (blank = off; an optional recall boost keyed to the server's domain vocabulary). The auth token is a **secret** — set it via env, not the JSON file:
82
82
 
83
83
  ```bash
84
84
  export HICORTEX_AUTH_TOKEN=hctx-<your-token> # or your custom token
@@ -86,7 +86,7 @@ export HICORTEX_AUTH_TOKEN=hctx-<your-token> # or your custom token
86
86
 
87
87
  Env overrides: `HICORTEX_URL`, `HICORTEX_AUTH_TOKEN`.
88
88
 
89
- > **`privacy_filter` is DEPRECATED** (plugin 0.7.2 / server 0.16.2). The server no longer filters on privacy — the `privacy` column is vestigial (stored, never filtered). The setting is still accepted for backward compatibility but is now a harmless no-op; setting it emits a one-time-per-process warning in the gateway log. For work/personal isolation, run a **separate Hicortex server** per scope rather than relying on in-server privacy filtering.
89
+ > **`privacy_filter` is REMOVED from setup** (plugin 0.7.4; deprecated since 0.7.2 / server 0.16.2). The server no longer filters on privacy — the `privacy` column is vestigial (stored, never filtered) so the setting was a no-op the setup flow still prompted for. New setups never see the question; existing config.json files that still carry the key are tolerated (one-time warning in the gateway log; safe to delete the line). For work/personal isolation, run a **separate Hicortex server** per scope rather than relying on in-server privacy filtering.
90
90
 
91
91
  ## Topology
92
92
 
@@ -36,65 +36,25 @@ CONFIG_SCHEMA: list[dict[str, Any]] = [
36
36
  "key": "hicortex_auth_token",
37
37
  "label": "Auth token",
38
38
  "description": (
39
- "Bearer token for the server. Omit (leave blank) when targeting "
40
- "localhost — the server bypasses auth there. Default token: "
41
- "hctx-default-token."
39
+ "Bearer token for the server. Leave blank when targeting "
40
+ "localhost — the server bypasses auth there. To find a remote "
41
+ "server's token, run `hicortex status` on the server machine "
42
+ "(or check ~/.hicortex/config.json there)."
42
43
  ),
43
44
  "secret": True,
44
45
  "env_var": "HICORTEX_AUTH_TOKEN",
45
46
  },
46
- {
47
- "key": "default_project",
48
- "label": "Default project",
49
- "description": "Optional project name to scope recall and capture.",
50
- "required": False,
51
- },
52
- {
53
- "key": "recall_limit",
54
- "label": "Recall limit",
55
- "description": (
56
- "Max memories returned per recall (default 5). Applies to the "
57
- "tools and the legacy pre-0.14 /search prefetch fallback only — "
58
- "the pushed recall index is sized by SERVER config (recallMaxItems)."
59
- ),
60
- "default": "5",
61
- "required": False,
62
- },
63
- {
64
- "key": "privacy_filter",
65
- "label": "Privacy filter (DEPRECATED)",
66
- "description": (
67
- "DEPRECATED since plugin 0.7.2 / server 0.16.2. The server no "
68
- "longer filters on privacy — the column is vestigial. This setting "
69
- "is now a harmless no-op: it is still accepted for backward "
70
- "compat but ignored. For work/personal isolation, run a separate "
71
- "Hicortex server per scope. (Historically: comma-separated privacy "
72
- "levels to include, e.g. WORK,PERSONAL.)"
73
- ),
74
- "default": "WORK,PERSONAL",
75
- "required": False,
76
- },
77
- {
78
- "key": "agent_name",
79
- "label": "Agent name (per-agent context)",
80
- "description": (
81
- "Identity sent as ?agent= when fetching the standing context layer, "
82
- "so this profile gets its own context (0.13). Leave blank to "
83
- "auto-derive from the running profile (HERMES_PROFILE / HERMES_HOME)."
84
- ),
85
- "required": False,
86
- },
87
- {
88
- "key": "mission_domains",
89
- "label": "Mission domains",
90
- "description": (
91
- "Comma-separated knowledge domains this agent works in (e.g. Health, "
92
- "or Finance,Work). Recall boosts memories tagged into these domains "
93
- "(soft — never excludes others). Pick from the domains in your "
94
- "Hicortex config; leave blank for a general-purpose agent."
95
- ),
96
- "required": False,
97
- },
47
+ # 0.7.6: setup asks ONLY url + token. default_project joined the
48
+ # config-only knobs (0.7.5 removed recall_limit / agent_name /
49
+ # mission_domains) after live-install feedback: "no human will understand
50
+ # what it is" a memory-attribution bucket is not a setup question.
51
+ # Config-only knobs (set directly in config.json, all have correct
52
+ # defaults): default_project (blank = unattributed), recall_limit (5;
53
+ # tools + legacy fallback only — the pushed index is SERVER-sized via
54
+ # recallMaxItems), agent_name (blank auto-derives from the running
55
+ # profile), mission_domains (blank = off).
56
+ # privacy_filter was removed outright in 0.7.4 (dead since server 0.16.2;
57
+ # tolerated at load with a one-time warning if an old file carries it).
98
58
  # NOTE: recall-only plugin — no capture config. Capture is handled by the
99
59
  # nightly server-side reader of each agent's session store.
100
60
  ]
@@ -130,7 +90,8 @@ def load_config() -> Dict[str, Any]:
130
90
  # Defaults
131
91
  cfg.setdefault("hicortex_url", "http://localhost:8787")
132
92
  cfg.setdefault("recall_limit", 5)
133
- cfg.setdefault("privacy_filter", "WORK,PERSONAL")
93
+ # No privacy_filter default — the setting is dead (see schema note) and
94
+ # must not be injected into new configs.
134
95
 
135
96
  # 0.16.2 deprecation: privacy_filter is a no-op now (server ignores privacy
136
97
  # entirely). Warn once per process if the profile explicitly sets it.
@@ -1,6 +1,6 @@
1
1
  name: hicortex
2
- version: 0.7.3
3
- description: "Self-learning memory for Hermes agents — every session is distilled into lessons overnight, and your agent wakes up wiser. Pushes a compact per-turn recall index (lazy-loaded with hicortex_get), injects fresh lessons plus a per-agent standing context block, and exposes the full 9-tool memory surface (search, get, recent, ingest, lessons, index, graph, update, delete) via a shared Hicortex server. Stdlib-only."
2
+ version: 0.7.8
3
+ description: "Self-learning memory for Hermes agents — every session is distilled into lessons overnight, and your agent wakes up wiser. Pushes a compact per-turn recall index (lazy-loaded with hicortex_get), injects fresh lessons plus a per-agent standing context block, and exposes the full 9-tool memory surface (search, get, recent, ingest, lessons, index, graph, update, delete) via a shared Hicortex server. Stdlib-only. AFTER INSTALL: run `hermes memory setup`, select hicortex, enter the server URL + token (see the token env var description for where to find it)."
4
4
  pip_dependencies: []
5
5
  hooks: []
6
6
  requires_env:
@@ -224,7 +224,10 @@ class HicortexProvider(MemoryProvider):
224
224
  self._recall_limit = int(cfg.get("recall_limit", 5))
225
225
  except (TypeError, ValueError):
226
226
  self._recall_limit = 5
227
- self._privacy = cfg.get("privacy_filter", "WORK,PERSONAL")
227
+ # privacy_filter removed (0.7.4): the server ignores privacy entirely;
228
+ # the dead setting is no longer read. _privacy stays at its inert
229
+ # default for the (equally ignored) wire parameter.
230
+ self._privacy = "WORK,PERSONAL"
228
231
  # #203 scope: declared knowledge domains for this role-bound agent
229
232
  # (e.g. a health-focused agent → Health). Soft affinity boost on
230
233
  # recall; never excludes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gamaze/hicortex",
3
- "version": "0.20.0",
3
+ "version": "0.20.1",
4
4
  "description": "Persistent agent identity for AI agents \u2014 a hand-edited identity layer, nightly-distilled experience, and lessons injected every session, shared across your whole fleet. Works with Hermes, OpenClaw, Claude Code, Pi, and opencode.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {