@gamaze/hicortex 0.16.8 → 0.16.10

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.
package/README.md CHANGED
@@ -203,7 +203,7 @@ Config at `~/.hicortex/config.json`. Created by `init`. Key options:
203
203
  | `numCtx` | Context window for ollama (default 8192, one value for all phases). Scoring uses ~850 tokens, so 2048 is ample; distill/reflect/classify need more for `detectChunkSize`'s chunk sizing. |
204
204
  | `enableThinking` | Toggle the model's internal reasoning ("thinking") stream for OpenAI-compatible endpoints (default false). Only meaningful for local chat-template-aware servers (ollama, mlx-lm); leave unset for cloud OpenAI/OpenRouter/Groq endpoints (they 400 on the unknown `chat_template_kwargs` field). |
205
205
  | `maxTokens` | Max output tokens for all phases (default 8192). A ceiling, not a target — the model stops early when done. |
206
- | `ollamaFlushEvery` | Flush ollama's accumulated memory every N scoring calls (default 0 = off). Workaround for ollama's memory-growth bug (~171 MB/call). N=15 caps a cycle at ~2.5 GB. Scoped to the fast tier (scoring) only. |
206
+ | `ollamaFlushEvery` | Flush ollama's accumulated memory every N scoring calls. **Off by default (0)** opt-in only for an **ollama** install whose runner RSS growth (~171 MB/call) swap-thrashes long consolidations on a RAM-constrained box; N=15 caps a cycle at ~2.5 GB. Gated on the provider being ollama (local **or** remote) — no effect for non-ollama providers. Only you can judge whether your ollama endpoint actually suffers the growth (a managed/cloud ollama host may not), so it stays off until you set it. |
207
207
  | `ollamaFlushWaitMs` | Milliseconds to wait after an ollama flush for the runner to exit + release memory (default 180000 = 3 min). |
208
208
  | `authToken` | Bearer token for endpoint auth. Generated on first `init` in server mode. Find the active token with `hicortex status` or in `~/.hicortex/config.json`. |
209
209
  | `corsAllowedOrigins` | Browser origins allowed to read cross-origin responses, e.g. `["https://ui.example.com"]`. **Empty by default** — the server sends no `Access-Control-Allow-Origin` and never `Allow-Credentials`, so no external web page can read its data. The bundled `/viz` and `/context/ui` pages are same-origin and need no entry. |
@@ -211,6 +211,7 @@ Config at `~/.hicortex/config.json`. Created by `init`. Key options:
211
211
  | `domains` | Your memory domain list (`[{name, description}]`). Scaffolded by `init`; edit freely — see [Memory Domains & Tags](#memory-domains--tags) |
212
212
  | `weakPrimaryFloor` | Minimum similarity for a no-fit memory to keep a weak domain association (default: 0.45) |
213
213
  | `moduleIndexTokenBudget` | Max tokens for domain index in lessons context (default: 500) |
214
+ | `lessonsLimit` | Max lessons injected into an agent's session-start context (default: 10). Lessons are ranked per session by project/domain affinity + recency + strength + access, so each session sees its most-relevant slice. Lower = leaner system prompts. |
214
215
  | `contextClients` | Which harnesses inject the [context layer](#context-layer) at session start (default `["cc"]`; `"all"` or any subset of `cc`/`hermes`/`oc`) |
215
216
  | `contextAgents` | Per-agent context modes (0.13): `{ "<id>": "override" \| "global" \| "off" }`. Absent + no `agents/<id>/` dir → every agent gets the global set. Boot-time (restart to apply) — see [Per-agent context](#per-agent-context-013) |
216
217
  | `agentName` | This install's per-agent context id sent as `?agent=`. **Unset by default** (CC shares the global context — no `?agent=` sent). Explicit opt-in via `init --agent-name <name>`; `init --agent-name ""` clears it. An empty/whitespace value equals unset |
@@ -29,3 +29,10 @@ export declare function readStrictBoolean(config: Record<string, unknown>, key:
29
29
  * value (e.g. ollamaFlushEvery).
30
30
  */
31
31
  export declare function readNonNegativeConfig(config: Record<string, unknown>, key: string, def: number): number;
32
+ /**
33
+ * Warn if the saved config carries keys that 0.16.8+ ignores. Call at every
34
+ * config read (daemon boot + nightly). The warning clears once the keys are
35
+ * removed and (for the model keys) the model is consolidated into
36
+ * llmModel/llmBaseUrl/llmProvider.
37
+ */
38
+ export declare function warnIgnoredConfigKeys(savedConfig: Record<string, unknown> | null | undefined): void;
@@ -16,6 +16,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.readPositiveConfig = readPositiveConfig;
17
17
  exports.readStrictBoolean = readStrictBoolean;
18
18
  exports.readNonNegativeConfig = readNonNegativeConfig;
19
+ exports.warnIgnoredConfigKeys = warnIgnoredConfigKeys;
19
20
  /**
20
21
  * Read a positive finite number from a config object. Returns `def` when the
21
22
  * key is absent OR present-but-invalid (with a warn in the latter case).
@@ -58,3 +59,49 @@ function readNonNegativeConfig(config, key, def) {
58
59
  console.warn(`[hicortex] config "${key}" = ${String(v)} is not a non-negative finite number — using default ${def}.`);
59
60
  return def;
60
61
  }
62
+ /**
63
+ * Config keys that ≤0.16.7 accepted and 0.16.8+ IGNORES. Two groups:
64
+ * - per-stage model keys + the nested `models` block (#231): one model now
65
+ * serves all phases, so distillation/reflection/classification silently run
66
+ * on `llmModel` — a quality downgrade if a larger model was on a distill/
67
+ * reflect tier.
68
+ * - `distillFallback` (#232): removed; strict mode is default. A `"local"`
69
+ * value no longer falls back — failures retry next run.
70
+ * Both were public (documented in the README config table). Warn loudly at the
71
+ * config boundary so neither change is silent.
72
+ *
73
+ * NOTE: this list is deliberately WIDER than the `HicortexConfig` type. In
74
+ * ≤0.16.7 most of these keys (the flat `distill*`/`reflect*` set and
75
+ * `distillFallback`) were NEVER declared in the interface — they were
76
+ * accepted-but-untyped, read loosely off the config object, with the README
77
+ * config table as their only public contract. So deriving this list from the
78
+ * type would miss them. The list is the README's documented keys; don't trim it
79
+ * to match the interface (a future audit that did so would silently re-introduce
80
+ * the ignored-key gap this warning exists to close).
81
+ */
82
+ const IGNORED_CONFIG_KEYS = [
83
+ "distillModel", "distillBaseUrl", "distillApiKey", "distillProvider",
84
+ "reflectModel", "reflectBaseUrl", "reflectApiKey", "reflectProvider",
85
+ "classifyModel", "classifyBaseUrl", "classifyApiKey", "classifyProvider",
86
+ "distillFallback",
87
+ ];
88
+ /**
89
+ * Warn if the saved config carries keys that 0.16.8+ ignores. Call at every
90
+ * config read (daemon boot + nightly). The warning clears once the keys are
91
+ * removed and (for the model keys) the model is consolidated into
92
+ * llmModel/llmBaseUrl/llmProvider.
93
+ */
94
+ function warnIgnoredConfigKeys(savedConfig) {
95
+ if (!savedConfig)
96
+ return;
97
+ const present = IGNORED_CONFIG_KEYS.filter((k) => savedConfig[k] !== undefined);
98
+ const hasModelsBlock = savedConfig.models !== undefined;
99
+ if (present.length === 0 && !hasModelsBlock)
100
+ return;
101
+ const detail = [...present, ...(hasModelsBlock ? ["models"] : [])].join(", ");
102
+ console.warn(`[hicortex] config has keys IGNORED since 0.16.8 (${detail}). They have no effect now. ` +
103
+ `Per-stage model keys / the \`models\` block: one model serves all phases — set ` +
104
+ `llmModel/llmBaseUrl/llmProvider (+ llmApiKey) to your intended model. ` +
105
+ `distillFallback: removed (strict mode is default — a failed distill retries next run). ` +
106
+ `Remove these keys to clear this warning. See the 0.16.8 changelog.`);
107
+ }
@@ -25,8 +25,18 @@ export declare function isPro(): boolean;
25
25
  export declare function maxMemoriesAllowed(): number;
26
26
  /** Always false — no cap is ever reached. */
27
27
  export declare function memoryCapReached(_currentCount: number): boolean;
28
- /** Always 20. */
29
- export declare function lessonsLimit(): number;
28
+ /**
29
+ * Max lessons injected into an agent's session-start context. Configurable via
30
+ * `config.lessonsLimit` (a positive integer); defaults to 10. Reuses
31
+ * `readPositiveConfig` so a present-but-invalid value (0, negative, NaN, wrong
32
+ * type) is rejected AT THE BOUNDARY with a warn — never silently. 0 is NOT
33
+ * honoured as "off" (use a real config switch if that's ever needed); it is
34
+ * invalid and falls back to 10 with a warning, so an operator can't
35
+ * accidentally silence lesson injection by typing 0.
36
+ */
37
+ export declare function lessonsLimit(config?: {
38
+ lessonsLimit?: unknown;
39
+ } | null): number;
30
40
  /** Always true — remote ingest is always allowed. */
31
41
  export declare function remoteIngestAllowed(): boolean;
32
42
  /** Direct read of the underlying features record. */
package/dist/features.js CHANGED
@@ -24,6 +24,7 @@ exports.getCurrentFeatures = getCurrentFeatures;
24
24
  const paths_js_1 = require("./paths.js");
25
25
  const license_js_1 = require("./license.js");
26
26
  const state_js_1 = require("./state.js");
27
+ const config_read_js_1 = require("./config-read.js");
27
28
  const DEFAULT_STATE_DIR = (0, paths_js_1.hicortexHome)();
28
29
  // A single canonical "full" feature set — no tiers.
29
30
  const FULL_FEATURES = {
@@ -90,9 +91,19 @@ function maxMemoriesAllowed() {
90
91
  function memoryCapReached(_currentCount) {
91
92
  return false;
92
93
  }
93
- /** Always 20. */
94
- function lessonsLimit() {
95
- return 20;
94
+ /**
95
+ * Max lessons injected into an agent's session-start context. Configurable via
96
+ * `config.lessonsLimit` (a positive integer); defaults to 10. Reuses
97
+ * `readPositiveConfig` so a present-but-invalid value (0, negative, NaN, wrong
98
+ * type) is rejected AT THE BOUNDARY with a warn — never silently. 0 is NOT
99
+ * honoured as "off" (use a real config switch if that's ever needed); it is
100
+ * invalid and falls back to 10 with a warning, so an operator can't
101
+ * accidentally silence lesson injection by typing 0.
102
+ */
103
+ function lessonsLimit(config) {
104
+ if (!config)
105
+ return 10;
106
+ return Math.floor((0, config_read_js_1.readPositiveConfig)({ lessonsLimit: config.lessonsLimit }, "lessonsLimit", 10));
96
107
  }
97
108
  /** Always true — remote ingest is always allowed. */
98
109
  function remoteIngestAllowed() {
package/dist/index.js CHANGED
@@ -50,6 +50,9 @@ const THIS_HARNESS = "oc";
50
50
  let serverUrl = DEFAULT_SERVER_URL;
51
51
  let authToken;
52
52
  let hicortexHome = HICORTEX_HOME;
53
+ /** Resolved plugin config captured at service start — used for tunable knobs
54
+ * (e.g. lessonsLimit) that injected context blocks read at hook time. */
55
+ let pluginConfig = null;
53
56
  /** Old-server guard (F2): 0 = not latched; otherwise the Date.now() epoch-ms
54
57
  * until which /recall-index is skipped after a 404 (pre-0.14 server). The
55
58
  * latch EXPIRES so a client-first rollout heals itself once the server is
@@ -152,7 +155,7 @@ async function buildLessonsBlock(project) {
152
155
  const { data } = await serverGet("/lessons", LESSONS_TIMEOUT_MS);
153
156
  if (!data || !data.lessons || data.lessons.length === 0)
154
157
  return null;
155
- const maxLessons = (0, features_js_1.lessonsLimit)();
158
+ const maxLessons = (0, features_js_1.lessonsLimit)(pluginConfig);
156
159
  const state = (0, state_js_1.loadState)(hicortexHome);
157
160
  const moduleIndex = data.moduleIndex ?? state.moduleIndex;
158
161
  const selected = await (0, extensions_js_1.getLessonSelector)().select(data.lessons, {
@@ -264,6 +267,7 @@ exports.default = {
264
267
  id: "hicortex-service",
265
268
  async start(ctx) {
266
269
  const config = (ctx.config ?? {});
270
+ pluginConfig = config;
267
271
  const log = ctx.logger
268
272
  ? (msg) => ctx.logger.info(msg)
269
273
  : console.log;
@@ -39,6 +39,8 @@ export interface ResolvedConfig {
39
39
  home: string;
40
40
  /** Per-agent context id sent as ?agent= (0.13); null → global (no param). */
41
41
  agentName: string | null;
42
+ /** Max lessons to inject (config.lessonsLimit, default 10). */
43
+ lessonsLimit?: number;
42
44
  }
43
45
  /**
44
46
  * Read ~/.hicortex/config.json and resolve the server URL + auth token, or
@@ -64,7 +64,13 @@ function resolveConfig() {
64
64
  // context. A configured agentName that sanitizes to null → agentId null too
65
65
  // (NO ?agent=), never a 400 that the fail-soft hook would silently swallow.
66
66
  const agentName = (0, context_store_js_1.resolveAgentIdentity)(config).agentId;
67
- return { serverUrl, authToken: config.authToken, home, agentName };
67
+ return {
68
+ serverUrl,
69
+ authToken: config.authToken,
70
+ home,
71
+ agentName,
72
+ lessonsLimit: typeof config.lessonsLimit === "number" ? config.lessonsLimit : undefined,
73
+ };
68
74
  }
69
75
  function authHeaders(authToken) {
70
76
  return authToken ? { "Authorization": `Bearer ${authToken}` } : {};
@@ -81,7 +87,7 @@ async function fetchLessonsBlock(cfg) {
81
87
  if (!resp.ok)
82
88
  return null;
83
89
  const data = await resp.json();
84
- const maxLessons = (0, features_js_1.lessonsLimit)();
90
+ const maxLessons = (0, features_js_1.lessonsLimit)(cfg);
85
91
  const moduleIndex = data.moduleIndex ?? (0, state_js_1.loadState)(cfg.home).moduleIndex;
86
92
  // The SessionStart hook runs in the session's working directory, whose last
87
93
  // path component matches the capture-side CC project name convention
@@ -57,6 +57,7 @@ const zod_1 = require("zod");
57
57
  const db_js_1 = require("./db.js");
58
58
  const llm_js_1 = require("./llm.js");
59
59
  const features_js_1 = require("./features.js");
60
+ const config_read_js_1 = require("./config-read.js");
60
61
  const state_js_1 = require("./state.js");
61
62
  const embedder_js_1 = require("./embedder.js");
62
63
  const storage = __importStar(require("./storage.js"));
@@ -373,6 +374,9 @@ async function startServer(options = {}) {
373
374
  // If nothing is configured: start recall-only with an unmissable warning.
374
375
  // One model serves all phases (#231) — no per-tier overlay here.
375
376
  const savedConfig = readConfigFile(stateDir);
377
+ // 0.16.8 upgrade guard: per-stage keys are silently ignored now. Warn loudly
378
+ // so a carried-over distill/reflect model doesn't silently downgrade quality.
379
+ (0, config_read_js_1.warnIgnoredConfigKeys)(savedConfig);
376
380
  // 0.16.2 activation gap: self-heal the agentId provenance field for
377
381
  // pre-0.16.2 server installs on first boot after upgrade. The server's own
378
382
  // nightly captures its sessions to localhost:8787/distill and needs this id;
package/dist/nightly.js CHANGED
@@ -219,6 +219,8 @@ async function runNightly(options = {}) {
219
219
  (0, state_js_1.migrateLegacyState)(stateDir);
220
220
  // Check mode: client or server
221
221
  const savedConfig = readNightlyConfig(stateDir);
222
+ // 0.16.8 upgrade guard: warn if ignored per-stage keys are still present.
223
+ (0, config_read_js_1.warnIgnoredConfigKeys)(savedConfig);
222
224
  // 0.16.2 activation gap: pre-0.16.2 installs never re-run init, so their
223
225
  // config has no agentId → capture sent source_agent_id: null forever (the
224
226
  // provenance feature was inert for the whole existing fleet). Self-heal on
@@ -366,6 +368,7 @@ async function runNightly(options = {}) {
366
368
  // Runs even if capture had transient failures (opens DB directly, independent
367
369
  // of the HTTP capture path). Full nightly only — capture-only runs are
368
370
  // intended to run more frequently than once daily.
371
+ let lessonsGenerated; // hoisted for telemetry; undefined when reflection didn't run (skipped) — bucketed apart from a real 0
369
372
  if (!dryRun && !captureOnly) {
370
373
  if (!llm || !llmConfig) {
371
374
  console.error("[hicortex] consolidation skipped: no LLM configured — run npx @gamaze/hicortex init");
@@ -390,6 +393,14 @@ async function runNightly(options = {}) {
390
393
  });
391
394
  console.log(`[hicortex] Consolidation ${report.status} in ${report.elapsed_seconds}s` +
392
395
  (report.stages.reflection ? ` (${report.stages.reflection.lessons_generated} lessons)` : ""));
396
+ // Only set when reflection actually RAN (not skipped). A skipped stage
397
+ // (e.g. endpoint offline, #232 fail-soft) must NOT collapse to 0 — that
398
+ // would make "endpoint down" indistinguishable from "prompt too tight"
399
+ // in the fleet aggregate. Leave undefined so the optional field is
400
+ // omitted and the aggregate buckets skipped runs separately.
401
+ const refl = report.stages.reflection;
402
+ if (refl && !refl.skipped)
403
+ lessonsGenerated = refl.lessons_generated;
393
404
  }
394
405
  }
395
406
  // Step 4: Update last-run timestamp.
@@ -434,6 +445,7 @@ async function runNightly(options = {}) {
434
445
  agent: agentType,
435
446
  mem: storage.countMemories(db),
436
447
  lessons: storage.getLessons(db, 365).length,
448
+ lessonsGenerated,
437
449
  sessions: batches.length,
438
450
  ok: !hadTransientFailure,
439
451
  shown: adoption.shown,
package/dist/prompts.d.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  /**
2
2
  * LLM prompt templates for memory consolidation and distillation.
3
3
  * Copied EXACTLY from the Python codebase (proven working prompts).
4
+ *
5
+ * SHIPPED SOURCE: this file is compiled into dist/ and published to npm + the
6
+ * public mirror (it is NOT in .publicignore). Any example, name, or detail in
7
+ * these prompts is therefore public. Use generic, anonymous examples — never
8
+ * real internal project/tool/host names or real incident specifics. The
9
+ * infra-name denylist cannot catch conceptual leaks, only known names.
4
10
  */
5
11
  /**
6
12
  * Importance scoring prompt. Takes a {memories_block} with indexed memories.
package/dist/prompts.js CHANGED
@@ -2,6 +2,12 @@
2
2
  /**
3
3
  * LLM prompt templates for memory consolidation and distillation.
4
4
  * Copied EXACTLY from the Python codebase (proven working prompts).
5
+ *
6
+ * SHIPPED SOURCE: this file is compiled into dist/ and published to npm + the
7
+ * public mirror (it is NOT in .publicignore). Any example, name, or detail in
8
+ * these prompts is therefore public. Use generic, anonymous examples — never
9
+ * real internal project/tool/host names or real incident specifics. The
10
+ * infra-name denylist cannot catch conceptual leaks, only known names.
5
11
  */
6
12
  Object.defineProperty(exports, "__esModule", { value: true });
7
13
  exports.importanceScoring = importanceScoring;
@@ -41,6 +47,9 @@ function reflection(memoriesBlock, recentLessons) {
41
47
 
42
48
  Like human learning: we grow fastest when we reinforce what works AND correct what doesn't. A system that only learns from mistakes becomes overly cautious. A system that only learns from successes never improves. The combination multiplies.
43
49
 
50
+ GENERALITY BAR (read carefully — the most important rule):
51
+ Every lesson MUST be a generalizable operating principle that transfers across contexts, agents, and projects. It is NOT: an incident report, a changelog entry, a one-event fact, a tool-specific recipe, or a note about a named entity. If a memory is only interesting as "what happened today", it is an EPISODE — do not emit a lesson for it. Abstract away specific tool names, hostnames, and incident details from the lesson text; state the transferable rule.
52
+
44
53
  Quality over quantity. 1-3 lessons is typical. An empty array [] is the CORRECT response when memories show routine competent work without noteworthy patterns, surprises, or friction. Do not manufacture lessons from nothing.
45
54
 
46
55
  LESSON TYPES:
@@ -56,15 +65,19 @@ Good reinforce: "Bundling related changes into a single PR with clear narrative
56
65
  Good reinforce: "When presenting multi-scenario analysis, show assumptions side-by-side so stakeholders evaluate trade-offs rather than reacting to isolated worst-cases"
57
66
  Good correct: "Always verify ALL substitution targets by diffing output — partial fixes cause silent failures"
58
67
  Good principle: "Gather evidence from logs before forming hypotheses — evidence-first debugging resolved issues 3x faster today"
68
+ Good principle: "When a long-running background agent survives a system migration as an orphan, explicitly unregister it before declaring the migration clean — orphans cause silent crash-loops"
59
69
  Bad lesson: "The deploy script had a bug" (restatement, not actionable)
70
+ Bad (incident note / changelog entry): "The graph resolver was fixed by adding a computed-at marker column" — that is a changelog entry, not a lesson
71
+ Bad (tool-specific decision): "Tool X is banned because it broke Tool Y's settings" — a one-tool decision, not transferable
72
+ Bad (single-event): "The chat client crashed after a system restore because a background agent was left orphaned" — an incident report, not a principle
60
73
 
61
74
  For each lesson, output a JSON object:
62
- - "lesson": Concise, actionable rule in imperative voice
75
+ - "lesson": Concise, actionable rule in imperative voice. State the transferable rule — abstract away specific tool names, hostnames, and incident details.
63
76
  - "type": "reinforce" | "correct" | "principle"
64
77
  - "project": "global" unless genuinely project-specific (project-specific lessons are still valuable)
65
78
  - "severity": "critical" | "important" | "minor"
66
79
  - "confidence": "high" | "medium" | "low"
67
- - "source_pattern": What triggered this (1 sentence, no personal data)
80
+ - "source_pattern": What triggered this (1 sentence, no personal data; may name the specific incident/tool here — but the \`lesson\` field itself stays generic)
68
81
 
69
82
  Severity guide:
70
83
  - "critical": Near-misses that could have caused data loss or security breach, even if caught in time. Also: recurring patterns that keep appearing despite prior corrections.
@@ -87,7 +100,7 @@ Focus on:
87
100
 
88
101
  Privacy: Never include personal data (names, health, finances, credentials) in lesson text. Abstract to the process level.
89
102
 
90
- Skip: isolated trivial actions, already-documented rules. However, if multiple small successes form a consistent pattern of quality, extract that pattern as a reinforcement.
103
+ Skip: isolated trivial actions, already-documented rules, incident notes, changelog entries, and tool-specific recipes. However, if multiple small successes form a consistent pattern of quality, extract that pattern as a reinforcement.
91
104
 
92
105
  Respond with a JSON array. Empty array [] is a valid response.`;
93
106
  }
@@ -13,6 +13,9 @@
13
13
  * client is never miscounted as "cc".
14
14
  * mem — total memory count
15
15
  * lessons — total lesson count
16
+ * lessonsGenerated — lessons created THIS run (server mode only; the per-run
17
+ * delta, distinct from `lessons` which is the corpus total). Lets a
18
+ * silent decline in reflection output be seen in the fleet aggregate.
16
19
  * sessions — sessions distilled this run
17
20
  * ok — nightly succeeded (true/false)
18
21
  * shown — sum of shown_count (server mode only)
@@ -76,6 +79,12 @@ export interface TelemetryPayload {
76
79
  shown?: number;
77
80
  uses?: number;
78
81
  cold?: number;
82
+ /**
83
+ * Lessons generated THIS run (server mode only). The per-run delta —
84
+ * `lessons` above is the corpus total, which drifts slowly via decay/prune
85
+ * and can't reveal a sudden drop in reflection output. 0.16.9+.
86
+ */
87
+ lessonsGenerated?: number;
79
88
  }
80
89
  /**
81
90
  * Check if telemetry is enabled. Disabled by:
package/dist/telemetry.js CHANGED
@@ -14,6 +14,9 @@
14
14
  * client is never miscounted as "cc".
15
15
  * mem — total memory count
16
16
  * lessons — total lesson count
17
+ * lessonsGenerated — lessons created THIS run (server mode only; the per-run
18
+ * delta, distinct from `lessons` which is the corpus total). Lets a
19
+ * silent decline in reflection output be seen in the fleet aggregate.
17
20
  * sessions — sessions distilled this run
18
21
  * ok — nightly succeeded (true/false)
19
22
  * shown — sum of shown_count (server mode only)
package/dist/types.d.ts CHANGED
@@ -300,6 +300,13 @@ export interface HicortexConfig {
300
300
  * doubled for margin). Only relevant when `ollamaFlushEvery` > 0.
301
301
  */
302
302
  ollamaFlushWaitMs?: number;
303
+ /**
304
+ * Max lessons injected into an agent's session-start context (default 10).
305
+ * Lessons are ranked per-session by project/domain affinity + recency +
306
+ * strength + access, so each session sees its most-relevant slice. Lower =
307
+ * leaner system prompts.
308
+ */
309
+ lessonsLimit?: number;
303
310
  }
304
311
  /** A config-owned life-sphere domain (see HicortexConfig.domains). */
305
312
  export interface DomainDef {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gamaze/hicortex",
3
- "version": "0.16.8",
3
+ "version": "0.16.10",
4
4
  "description": "Self-learning memory for AI agents — experience captured automatically, distilled into lessons overnight, shared across your whole fleet. Works with Hermes, OpenClaw, Claude Code, and Pi.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {