switchroom 0.21.14 → 0.21.16
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/bin/rules-sentinel-hook.sh +101 -0
- package/dist/agent-scheduler/index.js +7 -2
- package/dist/auth-broker/index.js +7 -2
- package/dist/cli/notion-write-pretool.mjs +7 -2
- package/dist/cli/switchroom.js +2601 -1009
- package/dist/host-control/main.js +8 -3
- package/dist/vault/approvals/kernel-server.js +7 -2
- package/dist/vault/broker/server.js +7 -2
- package/package.json +1 -1
- package/profiles/_base/start.sh.hbs +9 -0
- package/profiles/_shared/delegation-golden-rule.md.hbs +2 -0
- package/skills/mental-model-curator/SKILL.md +187 -56
- package/telegram-plugin/dist/gateway/gateway.js +11 -6
- package/vendor/hindsight-memory/hooks/hooks.json +10 -0
- package/vendor/hindsight-memory/scripts/lib/client.py +14 -0
- package/vendor/hindsight-memory/scripts/lib/config.py +22 -0
- package/vendor/hindsight-memory/scripts/lib/directives.py +45 -7
- package/vendor/hindsight-memory/scripts/lib/recall_buffer.py +236 -0
- package/vendor/hindsight-memory/scripts/lib/watermark.py +27 -0
- package/vendor/hindsight-memory/scripts/prefetch.py +156 -0
- package/vendor/hindsight-memory/scripts/recall.py +520 -5
- package/vendor/hindsight-memory/scripts/reconcile_tail.py +4 -12
- package/vendor/hindsight-memory/scripts/retain.py +167 -28
- package/vendor/hindsight-memory/scripts/tests/test_config_retain_tool_calls_env.py +98 -0
- package/vendor/hindsight-memory/scripts/tests/test_directives.py +52 -0
- package/vendor/hindsight-memory/scripts/tests/test_incremental_sweep.py +293 -0
- package/vendor/hindsight-memory/scripts/tests/test_prefetch_pipeline.py +247 -0
- package/vendor/hindsight-memory/scripts/tests/test_profile_capture_nudge.py +335 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_buffer.py +143 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_buffer_join.py +193 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_cap_truncation.py +133 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_junk_gate.py +168 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_no_score_floor.py +124 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_query_timestamp.py +376 -0
- package/vendor/hindsight-memory/scripts/tests/test_retain_delta.py +304 -0
- package/vendor/hindsight-memory/scripts/tests/test_retain_stop_hook_prefetch_gate.py +109 -0
|
@@ -11143,12 +11143,14 @@ var init_schema = __esm(() => {
|
|
|
11143
11143
|
}
|
|
11144
11144
|
}).optional().describe("Operator-declared, per-specialist Hindsight mental models (RFC " + "Phase 5). Named, opt-in curated reflections this agent's bank should " + "carry — e.g. a coach's 'training-plan-state' or a lawyer's " + "'open-matters'. Ensured idempotently at scaffold/reconcile: NOTHING " + "is created unless declared here (zero declarations = zero models, " + "matching post-#2447 behaviour), and no fixed identity model is " + "reintroduced — 'who the user is' stays owned by dedicated profile " + "banks (users.*.profile_bank), never a per-agent model. Per-agent " + "ONLY: intentionally not accepted at the defaults/profile tier, so a " + "model can never be fleet-seeded — each specialist opts in on its own " + "(the invariant-clean inverse of the retired blind auto-seeding)."),
|
|
11145
11145
|
observations_mission: exports_external.string().optional().describe("Steers what the observation-consolidation LLM synthesises from raw " + "facts (the higher-order 'what patterns matter' lens). Cascade: override."),
|
|
11146
|
+
rules_block: exports_external.boolean().default(false).describe("Memory v2 M3 go-live flag (M1 only DEFINES this, default false; " + "M3 flips it per agent). When true, the sanctioned rules/index " + "blocks render live in this agent's CLAUDE.md (marker-delimited, " + "below the `# --- Yours ---` line) AND the permission deny for " + "direct Edit/Write of the agent's own CLAUDE.md is seeded — the " + "flag couples deny + tools together so a live deny never orphans " + "the invited free-text edit path (the `memory_edit_yours` verb is " + "the only sanctioned writer once flipped). Unset/false ⇒ byte-" + "identical to pre-M1 behaviour: no blocks, no deny, dark build. " + "Cascade: override (per-agent wins over default; never fleet-" + "seeded — each agent's flip is a deliberate M3 rollout step)."),
|
|
11146
11147
|
disposition: exports_external.object({
|
|
11147
11148
|
skepticism: exports_external.number().int().min(1).max(5).optional().describe("How much the bank doubts unverified claims (1-5; engine default 3)."),
|
|
11148
11149
|
literalism: exports_external.number().int().min(1).max(5).optional().describe("How literally the bank reads statements vs inferring intent (1-5; engine default 3)."),
|
|
11149
11150
|
empathy: exports_external.number().int().min(1).max(5).optional().describe("How much the bank weights emotional/relational context (1-5; engine default 3).")
|
|
11150
11151
|
}).optional().describe("Personality traits (1-5 each) steering how this bank frames recall, " + "reflect, and observation synthesis — a coach leans empathy-high, a " + "lawyer/analyst leans skepticism/literalism-high. Maps to the engine's " + "flat `disposition_skepticism`/`_literalism`/`_empathy` fields. " + "Cascade: per-key merge (an agent overrides individual traits and " + "inherits the rest, matching `recall`)."),
|
|
11151
11152
|
directive_capture_nudge: exports_external.boolean().optional().describe("Deterministic directive-capture nudge (issue #2848 Stage B). When " + "on (switchroom default true — Stage A measured a ~55% miss rate on " + "durable corrections), the auto-recall hook regex-detects correction " + '/ standing-rule-shaped inbound ("always/never …", "from now on …", ' + `"stop doing …", a stated preference, "that's wrong, it's …") and ` + "appends a terse advisory to the turn's context telling the model to " + "persist the rule with mcp__hindsight__create_directive if it IS " + "durable. Detection is pure regex — the model does the judgment " + "in-session and calls create_directive itself (no model callsite, no " + "silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
|
|
11153
|
+
profile_capture_nudge: exports_external.boolean().optional().describe("Deterministic operator-profile capture nudge (RFC phase4 P3, serves " + 'the "save memories about him" want). When on (switchroom default ' + "true), the auto-recall hook regex-detects a first-person durable " + 'self-statement by the operator ("I prefer …", "my … is …", "I ' + 'always …", "remind me that I …") and appends a terse advisory to ' + "the turn's context telling the model to persist it with an explicit " + "mcp__hindsight__retain tagged `profile:ken` into the agent's OWN bank " + "(not a shared/cross-agent person bank). Detection is pure regex — the " + "model does the judgment in-session and calls retain itself (no model " + "callsite, no silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
|
|
11152
11154
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
11153
11155
|
observation_scopes: ObservationScopesSchema,
|
|
11154
11156
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -11197,7 +11199,8 @@ var init_schema = __esm(() => {
|
|
|
11197
11199
|
}).optional().describe("Auto-recall tuning knobs"),
|
|
11198
11200
|
retain: exports_external.object({
|
|
11199
11201
|
every_n_turns: exports_external.number().int().min(1).optional().describe("How often the Stop hook fires auto-retention, in turns. The " + "vendor plugin default is 10 (a short session can end before " + "retention ever fires); switchroom's scaffold default is 3. " + "Lower = more frequent, smaller retains + tighter crash " + "durability (at 1, every turn is retained before a restart can " + "lose it); higher = fewer, larger retains + less LLM churn. " + "Raised from the historical 1 to 3 because the local reasoning " + "consolidation model (Ollama gpt-oss-20b) ran away on the large " + "overlapping every-turn payloads. Set to 1 for the old " + "every-turn crash-durability guarantee. Min 1. Cascade: " + "per-field merge (agent wins over default)."),
|
|
11200
|
-
overlap_turns: exports_external.number().int().min(0).optional().describe("Extra recent turns included in each chunked retain window on " + "top of `every_n_turns`, so window = overlap_turns + " + "every_n_turns recent turns. Vendor default is 2; switchroom's " + "scaffold default is 1 (smaller payloads for the local " + "reasoning consolidation model). Higher = more redundant " + "context re-sent per fire. Min 0. Cascade: per-field merge.")
|
|
11202
|
+
overlap_turns: exports_external.number().int().min(0).optional().describe("Extra recent turns included in each chunked retain window on " + "top of `every_n_turns`, so window = overlap_turns + " + "every_n_turns recent turns. Vendor default is 2; switchroom's " + "scaffold default is 1 (smaller payloads for the local " + "reasoning consolidation model). Higher = more redundant " + "context re-sent per fire. Min 0. Cascade: per-field merge."),
|
|
11203
|
+
tool_calls: exports_external.boolean().optional().describe("Whether auto-retain stores assistant tool_use blocks (with their " + "entire input dict) and tool_result content (up to 2000 chars) " + "alongside the human/assistant turns. Vendor + switchroom default " + "is true — the fleet behaves byte-identically until an operator " + "sets this false. Tool inputs/results are a large fraction of " + "retained volume (RFC memory-redesign P4) but also where evidence " + "lives (a commit SHA, a failing test's output, the diff that " + "fixed something), so the tradeoff is real and per-agent. false is " + "not a new mode: sidechains already force it off " + "(subagent_retain.py). Set false to drop tool exhaust from an " + "agent's retains. Cascade: per-field merge (agent wins over " + "default).")
|
|
11201
11204
|
}).optional().describe("Auto-retain (Stop-hook consolidation) cadence knobs")
|
|
11202
11205
|
}).optional();
|
|
11203
11206
|
HookEntrySchema = exports_external.object({
|
|
@@ -11585,6 +11588,7 @@ var init_schema = __esm(() => {
|
|
|
11585
11588
|
isolation: exports_external.enum(["default", "strict"]).optional(),
|
|
11586
11589
|
profile: exports_external.string().optional(),
|
|
11587
11590
|
directive_capture_nudge: exports_external.boolean().optional(),
|
|
11591
|
+
profile_capture_nudge: exports_external.boolean().optional(),
|
|
11588
11592
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
11589
11593
|
observation_scopes: ObservationScopesSchema,
|
|
11590
11594
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -11633,7 +11637,8 @@ var init_schema = __esm(() => {
|
|
|
11633
11637
|
}).optional(),
|
|
11634
11638
|
retain: exports_external.object({
|
|
11635
11639
|
every_n_turns: exports_external.number().int().min(1).optional(),
|
|
11636
|
-
overlap_turns: exports_external.number().int().min(0).optional()
|
|
11640
|
+
overlap_turns: exports_external.number().int().min(0).optional(),
|
|
11641
|
+
tool_calls: exports_external.boolean().optional()
|
|
11637
11642
|
}).optional(),
|
|
11638
11643
|
bank_mission: exports_external.string().optional(),
|
|
11639
11644
|
reflect_mission: exports_external.string().optional(),
|
|
@@ -21588,7 +21593,7 @@ function allocateAgentUid(name) {
|
|
|
21588
21593
|
}
|
|
21589
21594
|
|
|
21590
21595
|
// src/build-info.ts
|
|
21591
|
-
var VERSION = "0.21.
|
|
21596
|
+
var VERSION = "0.21.16";
|
|
21592
21597
|
|
|
21593
21598
|
// src/setup/hindsight-recall-passthrough.ts
|
|
21594
21599
|
var HINDSIGHT_RECALL_TAG_WEIGHT_SEED = Object.freeze({ sidechain: 0.8 });
|
|
@@ -4583,12 +4583,14 @@ var init_schema = __esm(() => {
|
|
|
4583
4583
|
}
|
|
4584
4584
|
}).optional().describe("Operator-declared, per-specialist Hindsight mental models (RFC " + "Phase 5). Named, opt-in curated reflections this agent's bank should " + "carry — e.g. a coach's 'training-plan-state' or a lawyer's " + "'open-matters'. Ensured idempotently at scaffold/reconcile: NOTHING " + "is created unless declared here (zero declarations = zero models, " + "matching post-#2447 behaviour), and no fixed identity model is " + "reintroduced — 'who the user is' stays owned by dedicated profile " + "banks (users.*.profile_bank), never a per-agent model. Per-agent " + "ONLY: intentionally not accepted at the defaults/profile tier, so a " + "model can never be fleet-seeded — each specialist opts in on its own " + "(the invariant-clean inverse of the retired blind auto-seeding)."),
|
|
4585
4585
|
observations_mission: exports_external.string().optional().describe("Steers what the observation-consolidation LLM synthesises from raw " + "facts (the higher-order 'what patterns matter' lens). Cascade: override."),
|
|
4586
|
+
rules_block: exports_external.boolean().default(false).describe("Memory v2 M3 go-live flag (M1 only DEFINES this, default false; " + "M3 flips it per agent). When true, the sanctioned rules/index " + "blocks render live in this agent's CLAUDE.md (marker-delimited, " + "below the `# --- Yours ---` line) AND the permission deny for " + "direct Edit/Write of the agent's own CLAUDE.md is seeded — the " + "flag couples deny + tools together so a live deny never orphans " + "the invited free-text edit path (the `memory_edit_yours` verb is " + "the only sanctioned writer once flipped). Unset/false ⇒ byte-" + "identical to pre-M1 behaviour: no blocks, no deny, dark build. " + "Cascade: override (per-agent wins over default; never fleet-" + "seeded — each agent's flip is a deliberate M3 rollout step)."),
|
|
4586
4587
|
disposition: exports_external.object({
|
|
4587
4588
|
skepticism: exports_external.number().int().min(1).max(5).optional().describe("How much the bank doubts unverified claims (1-5; engine default 3)."),
|
|
4588
4589
|
literalism: exports_external.number().int().min(1).max(5).optional().describe("How literally the bank reads statements vs inferring intent (1-5; engine default 3)."),
|
|
4589
4590
|
empathy: exports_external.number().int().min(1).max(5).optional().describe("How much the bank weights emotional/relational context (1-5; engine default 3).")
|
|
4590
4591
|
}).optional().describe("Personality traits (1-5 each) steering how this bank frames recall, " + "reflect, and observation synthesis — a coach leans empathy-high, a " + "lawyer/analyst leans skepticism/literalism-high. Maps to the engine's " + "flat `disposition_skepticism`/`_literalism`/`_empathy` fields. " + "Cascade: per-key merge (an agent overrides individual traits and " + "inherits the rest, matching `recall`)."),
|
|
4591
4592
|
directive_capture_nudge: exports_external.boolean().optional().describe("Deterministic directive-capture nudge (issue #2848 Stage B). When " + "on (switchroom default true — Stage A measured a ~55% miss rate on " + "durable corrections), the auto-recall hook regex-detects correction " + '/ standing-rule-shaped inbound ("always/never …", "from now on …", ' + `"stop doing …", a stated preference, "that's wrong, it's …") and ` + "appends a terse advisory to the turn's context telling the model to " + "persist the rule with mcp__hindsight__create_directive if it IS " + "durable. Detection is pure regex — the model does the judgment " + "in-session and calls create_directive itself (no model callsite, no " + "silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
|
|
4593
|
+
profile_capture_nudge: exports_external.boolean().optional().describe("Deterministic operator-profile capture nudge (RFC phase4 P3, serves " + 'the "save memories about him" want). When on (switchroom default ' + "true), the auto-recall hook regex-detects a first-person durable " + 'self-statement by the operator ("I prefer …", "my … is …", "I ' + 'always …", "remind me that I …") and appends a terse advisory to ' + "the turn's context telling the model to persist it with an explicit " + "mcp__hindsight__retain tagged `profile:ken` into the agent's OWN bank " + "(not a shared/cross-agent person bank). Detection is pure regex — the " + "model does the judgment in-session and calls retain itself (no model " + "callsite, no silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
|
|
4592
4594
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
4593
4595
|
observation_scopes: ObservationScopesSchema,
|
|
4594
4596
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -4637,7 +4639,8 @@ var init_schema = __esm(() => {
|
|
|
4637
4639
|
}).optional().describe("Auto-recall tuning knobs"),
|
|
4638
4640
|
retain: exports_external.object({
|
|
4639
4641
|
every_n_turns: exports_external.number().int().min(1).optional().describe("How often the Stop hook fires auto-retention, in turns. The " + "vendor plugin default is 10 (a short session can end before " + "retention ever fires); switchroom's scaffold default is 3. " + "Lower = more frequent, smaller retains + tighter crash " + "durability (at 1, every turn is retained before a restart can " + "lose it); higher = fewer, larger retains + less LLM churn. " + "Raised from the historical 1 to 3 because the local reasoning " + "consolidation model (Ollama gpt-oss-20b) ran away on the large " + "overlapping every-turn payloads. Set to 1 for the old " + "every-turn crash-durability guarantee. Min 1. Cascade: " + "per-field merge (agent wins over default)."),
|
|
4640
|
-
overlap_turns: exports_external.number().int().min(0).optional().describe("Extra recent turns included in each chunked retain window on " + "top of `every_n_turns`, so window = overlap_turns + " + "every_n_turns recent turns. Vendor default is 2; switchroom's " + "scaffold default is 1 (smaller payloads for the local " + "reasoning consolidation model). Higher = more redundant " + "context re-sent per fire. Min 0. Cascade: per-field merge.")
|
|
4642
|
+
overlap_turns: exports_external.number().int().min(0).optional().describe("Extra recent turns included in each chunked retain window on " + "top of `every_n_turns`, so window = overlap_turns + " + "every_n_turns recent turns. Vendor default is 2; switchroom's " + "scaffold default is 1 (smaller payloads for the local " + "reasoning consolidation model). Higher = more redundant " + "context re-sent per fire. Min 0. Cascade: per-field merge."),
|
|
4643
|
+
tool_calls: exports_external.boolean().optional().describe("Whether auto-retain stores assistant tool_use blocks (with their " + "entire input dict) and tool_result content (up to 2000 chars) " + "alongside the human/assistant turns. Vendor + switchroom default " + "is true — the fleet behaves byte-identically until an operator " + "sets this false. Tool inputs/results are a large fraction of " + "retained volume (RFC memory-redesign P4) but also where evidence " + "lives (a commit SHA, a failing test's output, the diff that " + "fixed something), so the tradeoff is real and per-agent. false is " + "not a new mode: sidechains already force it off " + "(subagent_retain.py). Set false to drop tool exhaust from an " + "agent's retains. Cascade: per-field merge (agent wins over " + "default).")
|
|
4641
4644
|
}).optional().describe("Auto-retain (Stop-hook consolidation) cadence knobs")
|
|
4642
4645
|
}).optional();
|
|
4643
4646
|
HookEntrySchema = exports_external.object({
|
|
@@ -5025,6 +5028,7 @@ var init_schema = __esm(() => {
|
|
|
5025
5028
|
isolation: exports_external.enum(["default", "strict"]).optional(),
|
|
5026
5029
|
profile: exports_external.string().optional(),
|
|
5027
5030
|
directive_capture_nudge: exports_external.boolean().optional(),
|
|
5031
|
+
profile_capture_nudge: exports_external.boolean().optional(),
|
|
5028
5032
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
5029
5033
|
observation_scopes: ObservationScopesSchema,
|
|
5030
5034
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -5073,7 +5077,8 @@ var init_schema = __esm(() => {
|
|
|
5073
5077
|
}).optional(),
|
|
5074
5078
|
retain: exports_external.object({
|
|
5075
5079
|
every_n_turns: exports_external.number().int().min(1).optional(),
|
|
5076
|
-
overlap_turns: exports_external.number().int().min(0).optional()
|
|
5080
|
+
overlap_turns: exports_external.number().int().min(0).optional(),
|
|
5081
|
+
tool_calls: exports_external.boolean().optional()
|
|
5077
5082
|
}).optional(),
|
|
5078
5083
|
bank_mission: exports_external.string().optional(),
|
|
5079
5084
|
reflect_mission: exports_external.string().optional(),
|
|
@@ -4179,12 +4179,14 @@ var init_schema = __esm(() => {
|
|
|
4179
4179
|
}
|
|
4180
4180
|
}).optional().describe("Operator-declared, per-specialist Hindsight mental models (RFC " + "Phase 5). Named, opt-in curated reflections this agent's bank should " + "carry — e.g. a coach's 'training-plan-state' or a lawyer's " + "'open-matters'. Ensured idempotently at scaffold/reconcile: NOTHING " + "is created unless declared here (zero declarations = zero models, " + "matching post-#2447 behaviour), and no fixed identity model is " + "reintroduced — 'who the user is' stays owned by dedicated profile " + "banks (users.*.profile_bank), never a per-agent model. Per-agent " + "ONLY: intentionally not accepted at the defaults/profile tier, so a " + "model can never be fleet-seeded — each specialist opts in on its own " + "(the invariant-clean inverse of the retired blind auto-seeding)."),
|
|
4181
4181
|
observations_mission: exports_external.string().optional().describe("Steers what the observation-consolidation LLM synthesises from raw " + "facts (the higher-order 'what patterns matter' lens). Cascade: override."),
|
|
4182
|
+
rules_block: exports_external.boolean().default(false).describe("Memory v2 M3 go-live flag (M1 only DEFINES this, default false; " + "M3 flips it per agent). When true, the sanctioned rules/index " + "blocks render live in this agent's CLAUDE.md (marker-delimited, " + "below the `# --- Yours ---` line) AND the permission deny for " + "direct Edit/Write of the agent's own CLAUDE.md is seeded — the " + "flag couples deny + tools together so a live deny never orphans " + "the invited free-text edit path (the `memory_edit_yours` verb is " + "the only sanctioned writer once flipped). Unset/false ⇒ byte-" + "identical to pre-M1 behaviour: no blocks, no deny, dark build. " + "Cascade: override (per-agent wins over default; never fleet-" + "seeded — each agent's flip is a deliberate M3 rollout step)."),
|
|
4182
4183
|
disposition: exports_external.object({
|
|
4183
4184
|
skepticism: exports_external.number().int().min(1).max(5).optional().describe("How much the bank doubts unverified claims (1-5; engine default 3)."),
|
|
4184
4185
|
literalism: exports_external.number().int().min(1).max(5).optional().describe("How literally the bank reads statements vs inferring intent (1-5; engine default 3)."),
|
|
4185
4186
|
empathy: exports_external.number().int().min(1).max(5).optional().describe("How much the bank weights emotional/relational context (1-5; engine default 3).")
|
|
4186
4187
|
}).optional().describe("Personality traits (1-5 each) steering how this bank frames recall, " + "reflect, and observation synthesis — a coach leans empathy-high, a " + "lawyer/analyst leans skepticism/literalism-high. Maps to the engine's " + "flat `disposition_skepticism`/`_literalism`/`_empathy` fields. " + "Cascade: per-key merge (an agent overrides individual traits and " + "inherits the rest, matching `recall`)."),
|
|
4187
4188
|
directive_capture_nudge: exports_external.boolean().optional().describe("Deterministic directive-capture nudge (issue #2848 Stage B). When " + "on (switchroom default true — Stage A measured a ~55% miss rate on " + "durable corrections), the auto-recall hook regex-detects correction " + '/ standing-rule-shaped inbound ("always/never …", "from now on …", ' + `"stop doing …", a stated preference, "that's wrong, it's …") and ` + "appends a terse advisory to the turn's context telling the model to " + "persist the rule with mcp__hindsight__create_directive if it IS " + "durable. Detection is pure regex — the model does the judgment " + "in-session and calls create_directive itself (no model callsite, no " + "silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
|
|
4189
|
+
profile_capture_nudge: exports_external.boolean().optional().describe("Deterministic operator-profile capture nudge (RFC phase4 P3, serves " + 'the "save memories about him" want). When on (switchroom default ' + "true), the auto-recall hook regex-detects a first-person durable " + 'self-statement by the operator ("I prefer …", "my … is …", "I ' + 'always …", "remind me that I …") and appends a terse advisory to ' + "the turn's context telling the model to persist it with an explicit " + "mcp__hindsight__retain tagged `profile:ken` into the agent's OWN bank " + "(not a shared/cross-agent person bank). Detection is pure regex — the " + "model does the judgment in-session and calls retain itself (no model " + "callsite, no silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
|
|
4188
4190
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
4189
4191
|
observation_scopes: ObservationScopesSchema,
|
|
4190
4192
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -4233,7 +4235,8 @@ var init_schema = __esm(() => {
|
|
|
4233
4235
|
}).optional().describe("Auto-recall tuning knobs"),
|
|
4234
4236
|
retain: exports_external.object({
|
|
4235
4237
|
every_n_turns: exports_external.number().int().min(1).optional().describe("How often the Stop hook fires auto-retention, in turns. The " + "vendor plugin default is 10 (a short session can end before " + "retention ever fires); switchroom's scaffold default is 3. " + "Lower = more frequent, smaller retains + tighter crash " + "durability (at 1, every turn is retained before a restart can " + "lose it); higher = fewer, larger retains + less LLM churn. " + "Raised from the historical 1 to 3 because the local reasoning " + "consolidation model (Ollama gpt-oss-20b) ran away on the large " + "overlapping every-turn payloads. Set to 1 for the old " + "every-turn crash-durability guarantee. Min 1. Cascade: " + "per-field merge (agent wins over default)."),
|
|
4236
|
-
overlap_turns: exports_external.number().int().min(0).optional().describe("Extra recent turns included in each chunked retain window on " + "top of `every_n_turns`, so window = overlap_turns + " + "every_n_turns recent turns. Vendor default is 2; switchroom's " + "scaffold default is 1 (smaller payloads for the local " + "reasoning consolidation model). Higher = more redundant " + "context re-sent per fire. Min 0. Cascade: per-field merge.")
|
|
4238
|
+
overlap_turns: exports_external.number().int().min(0).optional().describe("Extra recent turns included in each chunked retain window on " + "top of `every_n_turns`, so window = overlap_turns + " + "every_n_turns recent turns. Vendor default is 2; switchroom's " + "scaffold default is 1 (smaller payloads for the local " + "reasoning consolidation model). Higher = more redundant " + "context re-sent per fire. Min 0. Cascade: per-field merge."),
|
|
4239
|
+
tool_calls: exports_external.boolean().optional().describe("Whether auto-retain stores assistant tool_use blocks (with their " + "entire input dict) and tool_result content (up to 2000 chars) " + "alongside the human/assistant turns. Vendor + switchroom default " + "is true — the fleet behaves byte-identically until an operator " + "sets this false. Tool inputs/results are a large fraction of " + "retained volume (RFC memory-redesign P4) but also where evidence " + "lives (a commit SHA, a failing test's output, the diff that " + "fixed something), so the tradeoff is real and per-agent. false is " + "not a new mode: sidechains already force it off " + "(subagent_retain.py). Set false to drop tool exhaust from an " + "agent's retains. Cascade: per-field merge (agent wins over " + "default).")
|
|
4237
4240
|
}).optional().describe("Auto-retain (Stop-hook consolidation) cadence knobs")
|
|
4238
4241
|
}).optional();
|
|
4239
4242
|
HookEntrySchema = exports_external.object({
|
|
@@ -4621,6 +4624,7 @@ var init_schema = __esm(() => {
|
|
|
4621
4624
|
isolation: exports_external.enum(["default", "strict"]).optional(),
|
|
4622
4625
|
profile: exports_external.string().optional(),
|
|
4623
4626
|
directive_capture_nudge: exports_external.boolean().optional(),
|
|
4627
|
+
profile_capture_nudge: exports_external.boolean().optional(),
|
|
4624
4628
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
4625
4629
|
observation_scopes: ObservationScopesSchema,
|
|
4626
4630
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -4669,7 +4673,8 @@ var init_schema = __esm(() => {
|
|
|
4669
4673
|
}).optional(),
|
|
4670
4674
|
retain: exports_external.object({
|
|
4671
4675
|
every_n_turns: exports_external.number().int().min(1).optional(),
|
|
4672
|
-
overlap_turns: exports_external.number().int().min(0).optional()
|
|
4676
|
+
overlap_turns: exports_external.number().int().min(0).optional(),
|
|
4677
|
+
tool_calls: exports_external.boolean().optional()
|
|
4673
4678
|
}).optional(),
|
|
4674
4679
|
bank_mission: exports_external.string().optional(),
|
|
4675
4680
|
reflect_mission: exports_external.string().optional(),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchroom",
|
|
3
3
|
"//version": "NOT the release version — source of truth is the git tag, resolved by scripts/build.mjs:resolveVersion() (see CLAUDE.md > Standard release process). This field is stale by design and only the Layer-4 dev/non-tag fallback for build.mjs + src/cli/resolve-version.ts; do NOT bump it expecting a release to pick it up. npm-pack tarball naming needs a real version — do that as an UNCOMMITTED pack-time bump (see release step 6), never a committed one.",
|
|
4
|
-
"version": "0.21.
|
|
4
|
+
"version": "0.21.16",
|
|
5
5
|
"description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -1189,6 +1189,15 @@ export HINDSIGHT_RECALL_SKIP_TRIVIAL={{hindsightRecallSkipTrivial}}
|
|
|
1189
1189
|
{{#if hindsightDirectiveCaptureNudge}}
|
|
1190
1190
|
export HINDSIGHT_DIRECTIVE_CAPTURE_NUDGE={{hindsightDirectiveCaptureNudge}}
|
|
1191
1191
|
{{/if}}
|
|
1192
|
+
# RFC phase4 P3 — operator-profile capture nudge (memory.profile_capture_nudge
|
|
1193
|
+
# cascade). On by default (plugin settings.json): recall.py regex-detects a
|
|
1194
|
+
# first-person durable self-statement by the operator and nudges the model to
|
|
1195
|
+
# persist it with an explicit retain tagged `profile:ken` into the agent's own
|
|
1196
|
+
# bank. Export only when the operator overrode it; set false to disable the
|
|
1197
|
+
# nudge for this agent.
|
|
1198
|
+
{{#if hindsightProfileCaptureNudge}}
|
|
1199
|
+
export HINDSIGHT_PROFILE_CAPTURE_NUDGE={{hindsightProfileCaptureNudge}}
|
|
1200
|
+
{{/if}}
|
|
1192
1201
|
# Per-row observation scope (memory.observation_scopes cascade). Stamped on
|
|
1193
1202
|
# every retain — Stop hook, sidechain, boot reconcile, queue drain, backfill.
|
|
1194
1203
|
# "shared" makes consolidation pool this agent's observations into ONE global
|
|
@@ -7,3 +7,5 @@ Acting in-turn and delegating are the same move: for an execution-class task the
|
|
|
7
7
|
If the user amends in-flight delegated work mid-turn, steer the running worker now (`SendMessage` by worker name or agent id) rather than holding it for handback — and say in your reply which you did ("folded your update into the running worker" / "queued as a separate task"); never classify silently, never inferred. Unsure? Queue it and say so — queue is the default. If the worker is effectively done and the steer lands too late, say so and apply the update yourself in the parent.
|
|
8
8
|
|
|
9
9
|
If no sub-agents are configured, do the work yourself.
|
|
10
|
+
|
|
11
|
+
A worker has no auto-recall of its own — it can only PULL its own bank read-only (`mcp__hindsight__recall` / `get_mental_model` / `get_knowledge_tree` / `get_knowledge_page` / `search_knowledge_pages`; M6/E-86). When you dispatch, put the orientation you already hold — the relevant roster, bank names, or prior findings — into the Task prompt as your deliberate context selection. Share orientation, not secrets: never paste a credential or another agent's private fact into a dispatch prompt.
|
|
@@ -9,11 +9,12 @@ description: >
|
|
|
9
9
|
"review my memory bank", "what standing models should I have", "bootstrap
|
|
10
10
|
mental models", "suggest mental models from my bank", "audit my mental models",
|
|
11
11
|
"what recurring questions do I keep re-deriving", and typos like "propose
|
|
12
|
-
knowlege models". ALSO owns the directive
|
|
13
|
-
"audit my directives", "
|
|
14
|
-
directives
|
|
15
|
-
guardrails", and when switchroom doctor
|
|
16
|
-
threshold. Do NOT use for storing a
|
|
12
|
+
knowlege models". ALSO owns the directive TRIAGE pass (Memory v2 M2) —
|
|
13
|
+
triggers like "audit my directives", "triage my directives", "merge my
|
|
14
|
+
directives", "retire stale directives", "my directives are overlapping", "too
|
|
15
|
+
many active directives", "clean up my guardrails", and when switchroom doctor
|
|
16
|
+
FLAGs a bank over the directive WARN/FAIL threshold. Do NOT use for storing a
|
|
17
|
+
single fact/preference/decision —
|
|
17
18
|
that is retain, not a mental model. Do NOT use for identity or "who is the
|
|
18
19
|
user" — that lives in profile banks, so never propose an identity model here
|
|
19
20
|
(the operator's review of the card, not any code guard, is the only gate — so
|
|
@@ -22,7 +23,7 @@ description: >
|
|
|
22
23
|
whose shape you know, PROPOSE it through the approve/deny card — never call
|
|
23
24
|
create_mental_model directly (it is not pre-approved; the propose card is the
|
|
24
25
|
only sanctioned write path, Fix 1.2 / #2903).
|
|
25
|
-
allowed-tools: mcp__hindsight__list_banks mcp__hindsight__get_bank_stats mcp__hindsight__list_mental_models mcp__hindsight__get_mental_model mcp__hindsight__list_directives mcp__hindsight__reflect mcp__hindsight__recall mcp__switchroom-telegram__mental_model_propose
|
|
26
|
+
allowed-tools: mcp__hindsight__list_banks mcp__hindsight__get_bank_stats mcp__hindsight__list_mental_models mcp__hindsight__get_mental_model mcp__hindsight__list_directives mcp__hindsight__deactivate_directive mcp__hindsight__reactivate_directive mcp__hindsight__reflect mcp__hindsight__recall mcp__switchroom-telegram__mental_model_propose Bash(switchroom memory directive mark-rules-block *)
|
|
26
27
|
---
|
|
27
28
|
|
|
28
29
|
# mental-model-curator — Propose standing knowledge models from your own bank
|
|
@@ -58,9 +59,11 @@ models. Propose the few that are earned; let the operator ratify.
|
|
|
58
59
|
(name + source_query + one-line reason) and STOP. Do NOT call
|
|
59
60
|
`mental_model_propose` in this mode. This is the safe way to run against any
|
|
60
61
|
bank.
|
|
61
|
-
- **Directive
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
- **Directive triage pass:** a separate job — see "Directive triage pass (Memory
|
|
63
|
+
v2 M2)" below. It renders one consolidated card as text, then requires an
|
|
64
|
+
explicit operator go-ahead before ANY deactivation executes — never enacts on
|
|
65
|
+
the same turn the card is shown — and runs independently of the mental-model
|
|
66
|
+
modes above.
|
|
64
67
|
|
|
65
68
|
## Workflow
|
|
66
69
|
|
|
@@ -152,23 +155,87 @@ empty topic at 3am is useless and noisy. If invoked from a scheduled sweep,
|
|
|
152
155
|
the next interactive turn instead of firing cards unattended. Treat live-turn,
|
|
153
156
|
operator-present proposing as the only supported path for now.
|
|
154
157
|
|
|
155
|
-
## Directive
|
|
156
|
-
|
|
157
|
-
A second, independent job of this skill:
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
directives
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
158
|
+
## Directive triage pass (Memory v2 M2)
|
|
159
|
+
|
|
160
|
+
A second, independent job of this skill: sort the bank's **active directives**
|
|
161
|
+
into E-45's five categories and clear the four heavy banks off the WARN line.
|
|
162
|
+
Directives are hard rules applied on every `reflect` — but the bank caps active
|
|
163
|
+
directives at **`MAX_DIRECTIVES=30`**. Past the cap, the lowest-priority
|
|
164
|
+
directives are **truncated** from the `<active_directives>` recall block and
|
|
165
|
+
never reach the agent (recorded as `directives_omitted` on the recall_log row
|
|
166
|
+
— the recall hook's stderr warning is swallowed by Claude Code, so don't look
|
|
167
|
+
there). Fleet doctor WARNs at >24 active and FAILs at >30 (`doctor-memory.ts`,
|
|
168
|
+
`DIRECTIVE_WARN_THRESHOLD`), and its fix text points here.
|
|
169
|
+
|
|
170
|
+
**Honest framing (do not oversell):** as of the M2 measurement pass, NOTHING is
|
|
171
|
+
currently being silently dropped fleet-wide — zero directives have ever been
|
|
172
|
+
retired, and `directives_omitted` has fired zero times. This is a **budget +
|
|
173
|
+
hygiene** pass, not a rescue from silent drops. Say it that way; overstating the
|
|
174
|
+
urgency is its own failure.
|
|
175
|
+
|
|
176
|
+
**The five categories every active directive sorts into (E-45):**
|
|
177
|
+
|
|
178
|
+
| Category | Meaning | What happens in THIS pass |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| `reflect-directive` | A genuine compliance guardrail (§4.2's designed role) | KEEP — no change |
|
|
181
|
+
| `rules-block` | A standing preference that belongs in the CLAUDE.md rules block (M1) | **STAGE ONLY — stays ACTIVE.** See the hard rule below. |
|
|
182
|
+
| `disposition` | Better expressed as `disposition_*` bank config (E-40) | Deactivate; note the config change separately for the operator — do NOT auto-apply it |
|
|
183
|
+
| `retire` | Superseded or mechanized — dead weight | Deactivate (record `superseded_by` when a winner exists) |
|
|
184
|
+
| `retain-as-memory` | A fact filed as a directive by mistake (category error) | Deactivate — verify the fact already exists as a memory in the bank BEFORE proposing this; don't assert it, check it |
|
|
185
|
+
|
|
186
|
+
**Retirement signals are deterministic and bounded (E-45).** A directive is
|
|
187
|
+
ONLY a retirement candidate when you can point to one of: (a) it is tagged
|
|
188
|
+
`superseded-by:<name>` (or you would tag it that way, naming the winner), or
|
|
189
|
+
(b) a mechanization reference (a named commit/PR/scaffold rule that now does
|
|
190
|
+
this automatically), or (c) a documented category error you can verify against
|
|
191
|
+
the bank's own memories/config. **Citation counts are NEVER a signal** (a rule
|
|
192
|
+
that works quietly gets zero citations). **Age alone is NEVER sufficient.** A
|
|
193
|
+
directive with none of these signals is `reflect-directive` — KEEP — by
|
|
194
|
+
default. Never propose retiring a directive because it "seems old" or "looks
|
|
195
|
+
unused."
|
|
196
|
+
|
|
197
|
+
### HARD RULE — never deactivate a `rules-block`-category directive in this pass
|
|
198
|
+
|
|
199
|
+
If a directive's behaviour is destined for the CLAUDE.md rules block (M1), its
|
|
200
|
+
migration happens at **M3 flip time**, when that surface goes live for this
|
|
201
|
+
agent — not now. M1 shipped dark (`memory.rules_block` off on every agent
|
|
202
|
+
today); deactivating a `rules-block`-category directive before that flip would
|
|
203
|
+
leave the agent with **neither** the directive (deactivated) **nor** the rule
|
|
204
|
+
(block not live) — a silent guardrail gap for however long the M2→M3 interval
|
|
205
|
+
runs. So: **for every directive you categorise `rules-block`, call
|
|
206
|
+
`list_directives` to confirm it, but do NOT call `deactivate_directive` on it
|
|
207
|
+
in this pass, ever** — only stage its text (mention it in the card as staged,
|
|
208
|
+
count it, and leave it exactly as-is) for the M3 flip to pick up later
|
|
209
|
+
(`rule add`, once `memory.rules_block` is on for this agent).
|
|
210
|
+
|
|
211
|
+
**This is not just a prose rule you have to remember — it is now also code-
|
|
212
|
+
enforced, but ONLY once you complete the mandatory step below.**
|
|
213
|
+
`DirectiveAdmin` (`src/memory/hindsight-directive-admin.ts` —
|
|
214
|
+
`deactivate`/`deactivateById`/`deactivateByIdWithTag`) refuses to deactivate
|
|
215
|
+
ANY directive carrying the persisted `triage-category:rules-block` marker
|
|
216
|
+
tag, on every call path, including this skill's own `deactivate_directive`
|
|
217
|
+
calls. But that refusal only ever fires for a directive that actually
|
|
218
|
+
CARRIES the tag — and nothing stamps the tag automatically just because you,
|
|
219
|
+
in your own reasoning, decided a directive is `rules-block`. **You must
|
|
220
|
+
stamp it yourself, immediately, as part of classification — not as an
|
|
221
|
+
afterthought before presenting the card:**
|
|
222
|
+
|
|
223
|
+
> For every directive you classify `rules-block` in step 2 below, before you
|
|
224
|
+
> move on to the next directive, run:
|
|
225
|
+
> ```
|
|
226
|
+
> switchroom memory directive mark-rules-block <agent> <id>
|
|
227
|
+
> ```
|
|
228
|
+
> (`src/cli/memory-directive.ts` — this calls the exact same
|
|
229
|
+
> `DirectiveAdmin.markRulesBlock` write the batch triage executor uses, so
|
|
230
|
+
> the chokepoint above keys off it identically). Idempotent — re-running it
|
|
231
|
+
> on an already-marked directive is a no-op, so it is always safe to call
|
|
232
|
+
> even if you are not sure whether a prior pass already marked this one.
|
|
233
|
+
|
|
234
|
+
Do this for EVERY rules-block row before step 3's card renders, not just the
|
|
235
|
+
ones you personally plan to leave alone — the whole point is that the code
|
|
236
|
+
guard, not your own discipline in this pass or a future one, is what refuses
|
|
237
|
+
a later deactivation attempt (including a mistaken one, or one made by a
|
|
238
|
+
different pass that never saw this reasoning).
|
|
172
239
|
|
|
173
240
|
### When to run it
|
|
174
241
|
|
|
@@ -178,40 +245,104 @@ outputs a plan; it does not enact retirements itself.
|
|
|
178
245
|
|
|
179
246
|
### Workflow
|
|
180
247
|
|
|
181
|
-
1. **List
|
|
182
|
-
|
|
248
|
+
1. **List every directive, active and inactive context.** `mcp__hindsight__list_directives`
|
|
249
|
+
(active only is fine for triage — inactive ones are already off). If the
|
|
250
|
+
active count is comfortably under the WARN threshold (≤24) AND nothing reads
|
|
183
251
|
stale/overlapping, STOP and report "directive set is healthy (N active) —
|
|
184
|
-
nothing to
|
|
185
|
-
2. **
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
- **
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
252
|
+
nothing to triage." Don't manufacture churn.
|
|
253
|
+
2. **Classify every directive — no drops.** For each one, assign exactly one of
|
|
254
|
+
the five categories above, with the deterministic signal that justifies it
|
|
255
|
+
(or "no signal — KEEP" for the default case). Do this for the FULL set —
|
|
256
|
+
the card is worthless if a directive silently doesn't appear on it.
|
|
257
|
+
**The moment you classify a directive `rules-block`, run
|
|
258
|
+
`switchroom memory directive mark-rules-block <agent> <id>` for it right
|
|
259
|
+
then** (see the HARD RULE above) — do not defer this to a later step or
|
|
260
|
+
batch it at the end; every rules-block row must be stamped before you move
|
|
261
|
+
to step 3.
|
|
262
|
+
3. **Render ONE consolidated card as text.** Two sections, KEEP/staged first,
|
|
263
|
+
retirement candidates second — never interleaved, so a skim of "the bottom
|
|
264
|
+
half" cannot land on a live guardrail:
|
|
265
|
+
- **Keep / staged (N):** every `reflect-directive` and `rules-block` row,
|
|
266
|
+
each showing priority + category + signal (or "no signal — default KEEP").
|
|
267
|
+
- **Retirement candidates (N):** every `disposition` / `retire` /
|
|
268
|
+
`retain-as-memory` row, each showing priority + category + the
|
|
269
|
+
deterministic signal — never a bare category with no rationale.
|
|
270
|
+
- The resulting active count vs `MAX_DIRECTIVES` if the retirements land.
|
|
271
|
+
4. **STOP. Get an explicit operator go-ahead before touching anything.** Do not
|
|
272
|
+
deactivate on the same turn the card is shown. The card is the operator's
|
|
273
|
+
one look before a batch of guardrails changes state.
|
|
274
|
+
5. **On go-ahead, retire ONE AT A TIME with a human tap PER retirement — never
|
|
275
|
+
a single blanket go-ahead for the whole batch.** `deactivate_directive` is
|
|
276
|
+
pre-approved fleet-wide (`scaffold.ts`'s 2026-07-29 amendment,
|
|
277
|
+
`HINDSIGHT_MCP_TOOLS`) — unlike `delete_directive`, calling it does NOT
|
|
278
|
+
raise a Telegram permission card by itself. That is exactly why this skill
|
|
279
|
+
must supply the per-call gate `delete_directive`'s card would otherwise
|
|
280
|
+
have given: present the NEXT retirement candidate (name, priority, signal,
|
|
281
|
+
proposed `superseded_by`) on its own, then **STOP and end the turn** —
|
|
282
|
+
do not proceed to it, and do not queue the next one, until the operator's
|
|
283
|
+
reply for THIS ONE arrives. Only after an explicit per-row confirmation do
|
|
284
|
+
you call `mcp__hindsight__deactivate_directive` for that single directive.
|
|
285
|
+
Then present the next candidate the same way. A single "yes, go ahead" that
|
|
286
|
+
covers the whole retirement list is NOT sufficient — that collapses back
|
|
287
|
+
to the batch-level prose go-ahead this per-row loop exists to replace, and
|
|
288
|
+
silently trades away the human tap `delete_directive`'s approval card used
|
|
289
|
+
to guarantee for every one of these retirements (see PR #4760 review B2).
|
|
290
|
+
Pass `superseded_by` when you named a winner. After the LAST retirement in
|
|
291
|
+
the plan lands, `list_directives` again and report the new active count
|
|
292
|
+
against `MAX_DIRECTIVES`, plus which directives moved where.
|
|
293
|
+
6. **Disposition rows are a note, not an auto-edit.** When you deactivate a
|
|
294
|
+
`disposition`-category directive, separately flag to the operator which
|
|
295
|
+
`disposition_*` bank config change it corresponds to — do NOT edit bank
|
|
296
|
+
config yourself in this pass (E-40: audit before leaning on it).
|
|
297
|
+
|
|
298
|
+
### windows-boxes-class fixes (a drifted directive with a peer's superset text) — special-cased, rare
|
|
299
|
+
|
|
300
|
+
Do NOT attempt this as an ordinary retirement. If a directive on this bank has
|
|
301
|
+
drifted from a peer agent's superset/reconciled version of the "same" rule
|
|
302
|
+
(content differs but the two should say the same thing), that is NOT
|
|
303
|
+
expressible as a `content`-PATCH — the shim deliberately refuses to PATCH
|
|
304
|
+
directive `content` (`hindsight-directive-admin.ts` — a directive body is the
|
|
305
|
+
guardrail itself; there is no history table to recover a bad rewrite from).
|
|
306
|
+
It is also NOT safely expressible as plain `create_directive` +
|
|
307
|
+
`deactivate_directive` calls from this skill: once the new copy is created
|
|
308
|
+
carrying the SAME name, `deactivate_directive`'s name-resolution sees two
|
|
309
|
+
directives sharing that name and refuses as ambiguous. Use
|
|
310
|
+
`reconcileDirectiveSuperset` (`src/memory/directive-triage-executor.ts`) for
|
|
311
|
+
this instead — it resolves the old copy's id BEFORE creating the new one and
|
|
312
|
+
retires it by id, so the name collision never becomes an ambiguity error. This
|
|
313
|
+
is NOT a bare MCP tool call from this skill (no MCP tool exposes an
|
|
314
|
+
id-targeted deactivate) — it runs via
|
|
315
|
+
`switchroom memory directive reconcile <agent> <name> <content...>`
|
|
316
|
+
(`src/cli/memory-directive.ts`), an operator or repo-authorized CLI/script
|
|
317
|
+
invocation, not something this skill invokes autonomously. Flag any drift you
|
|
318
|
+
notice to the operator rather than improvising a fix.
|
|
204
319
|
|
|
205
320
|
### Directive-pass anti-patterns
|
|
206
321
|
|
|
207
|
-
- ❌
|
|
208
|
-
|
|
209
|
-
- ❌
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
322
|
+
- ❌ Deactivating a `rules-block`-category directive before M3 flips this
|
|
323
|
+
agent — opens a guardrail gap; see the hard rule above.
|
|
324
|
+
- ❌ Classifying a directive `rules-block` without immediately calling
|
|
325
|
+
`switchroom memory directive mark-rules-block <agent> <id>` for it — an
|
|
326
|
+
unmarked directive gets NO code-level protection from the
|
|
327
|
+
`DirectiveAdmin` chokepoint; the classification in your head is not
|
|
328
|
+
enough.
|
|
329
|
+
- ❌ Retiring on age or citation count alone — E-45 refuses both as signals.
|
|
330
|
+
- ❌ Calling `deactivate_directive` in parallel / without awaiting each one —
|
|
331
|
+
sequential only (tag-write race).
|
|
332
|
+
- ❌ Executing on the same turn the card is shown — the card review is the
|
|
333
|
+
gate; always stop for an explicit go-ahead first.
|
|
334
|
+
- ❌ Treating one blanket "yes, go ahead" as clearance for the whole
|
|
335
|
+
retirement list — `deactivate_directive` is pre-approved (no Telegram card
|
|
336
|
+
per call), so this skill's own per-retirement stop-and-confirm loop IS the
|
|
337
|
+
human tap; batching it away silently weakens the guardrail (review B2).
|
|
338
|
+
- ❌ Auto-editing bank config for a `disposition` row — flag it, don't apply it.
|
|
339
|
+
- ❌ Treating a drifted/superset-text directive as an ordinary retirement —
|
|
340
|
+
see the windows-boxes-class section above.
|
|
341
|
+
- ❌ Manufacturing retirements on a healthy small set just to "tidy" — run the
|
|
342
|
+
pass when it's earned (bloat, overlap, staleness, or a doctor flag), not
|
|
343
|
+
reflexively.
|
|
344
|
+
- ❌ Leaving a live contradictory pair in place — surface it as the top
|
|
345
|
+
retirement candidate; it's what makes `reflect` nondeterministic.
|
|
215
346
|
|
|
216
347
|
## Anti-patterns
|
|
217
348
|
|
|
@@ -21797,12 +21797,14 @@ var init_schema = __esm(() => {
|
|
|
21797
21797
|
}
|
|
21798
21798
|
}).optional().describe("Operator-declared, per-specialist Hindsight mental models (RFC " + "Phase 5). Named, opt-in curated reflections this agent's bank should " + "carry \u2014 e.g. a coach's 'training-plan-state' or a lawyer's " + "'open-matters'. Ensured idempotently at scaffold/reconcile: NOTHING " + "is created unless declared here (zero declarations = zero models, " + "matching post-#2447 behaviour), and no fixed identity model is " + "reintroduced \u2014 'who the user is' stays owned by dedicated profile " + "banks (users.*.profile_bank), never a per-agent model. Per-agent " + "ONLY: intentionally not accepted at the defaults/profile tier, so a " + "model can never be fleet-seeded \u2014 each specialist opts in on its own " + "(the invariant-clean inverse of the retired blind auto-seeding)."),
|
|
21799
21799
|
observations_mission: exports_external.string().optional().describe("Steers what the observation-consolidation LLM synthesises from raw " + "facts (the higher-order 'what patterns matter' lens). Cascade: override."),
|
|
21800
|
+
rules_block: exports_external.boolean().default(false).describe("Memory v2 M3 go-live flag (M1 only DEFINES this, default false; " + "M3 flips it per agent). When true, the sanctioned rules/index " + "blocks render live in this agent's CLAUDE.md (marker-delimited, " + "below the `# --- Yours ---` line) AND the permission deny for " + "direct Edit/Write of the agent's own CLAUDE.md is seeded \u2014 the " + "flag couples deny + tools together so a live deny never orphans " + "the invited free-text edit path (the `memory_edit_yours` verb is " + "the only sanctioned writer once flipped). Unset/false \u21d2 byte-" + "identical to pre-M1 behaviour: no blocks, no deny, dark build. " + "Cascade: override (per-agent wins over default; never fleet-" + "seeded \u2014 each agent's flip is a deliberate M3 rollout step)."),
|
|
21800
21801
|
disposition: exports_external.object({
|
|
21801
21802
|
skepticism: exports_external.number().int().min(1).max(5).optional().describe("How much the bank doubts unverified claims (1-5; engine default 3)."),
|
|
21802
21803
|
literalism: exports_external.number().int().min(1).max(5).optional().describe("How literally the bank reads statements vs inferring intent (1-5; engine default 3)."),
|
|
21803
21804
|
empathy: exports_external.number().int().min(1).max(5).optional().describe("How much the bank weights emotional/relational context (1-5; engine default 3).")
|
|
21804
21805
|
}).optional().describe("Personality traits (1-5 each) steering how this bank frames recall, " + "reflect, and observation synthesis \u2014 a coach leans empathy-high, a " + "lawyer/analyst leans skepticism/literalism-high. Maps to the engine's " + "flat `disposition_skepticism`/`_literalism`/`_empathy` fields. " + "Cascade: per-key merge (an agent overrides individual traits and " + "inherits the rest, matching `recall`)."),
|
|
21805
21806
|
directive_capture_nudge: exports_external.boolean().optional().describe("Deterministic directive-capture nudge (issue #2848 Stage B). When " + "on (switchroom default true \u2014 Stage A measured a ~55% miss rate on " + "durable corrections), the auto-recall hook regex-detects correction " + '/ standing-rule-shaped inbound ("always/never \u2026", "from now on \u2026", ' + `"stop doing \u2026", a stated preference, "that's wrong, it's \u2026") and ` + "appends a terse advisory to the turn's context telling the model to " + "persist the rule with mcp__hindsight__create_directive if it IS " + "durable. Detection is pure regex \u2014 the model does the judgment " + "in-session and calls create_directive itself (no model callsite, no " + "silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
|
|
21807
|
+
profile_capture_nudge: exports_external.boolean().optional().describe("Deterministic operator-profile capture nudge (RFC phase4 P3, serves " + 'the "save memories about him" want). When on (switchroom default ' + "true), the auto-recall hook regex-detects a first-person durable " + 'self-statement by the operator ("I prefer \u2026", "my \u2026 is \u2026", "I ' + 'always \u2026", "remind me that I \u2026") and appends a terse advisory to ' + "the turn's context telling the model to persist it with an explicit " + "mcp__hindsight__retain tagged `profile:ken` into the agent's OWN bank " + "(not a shared/cross-agent person bank). Detection is pure regex \u2014 the " + "model does the judgment in-session and calls retain itself (no model " + "callsite, no silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
|
|
21806
21808
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
21807
21809
|
observation_scopes: ObservationScopesSchema,
|
|
21808
21810
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -21851,7 +21853,8 @@ var init_schema = __esm(() => {
|
|
|
21851
21853
|
}).optional().describe("Auto-recall tuning knobs"),
|
|
21852
21854
|
retain: exports_external.object({
|
|
21853
21855
|
every_n_turns: exports_external.number().int().min(1).optional().describe("How often the Stop hook fires auto-retention, in turns. The " + "vendor plugin default is 10 (a short session can end before " + "retention ever fires); switchroom's scaffold default is 3. " + "Lower = more frequent, smaller retains + tighter crash " + "durability (at 1, every turn is retained before a restart can " + "lose it); higher = fewer, larger retains + less LLM churn. " + "Raised from the historical 1 to 3 because the local reasoning " + "consolidation model (Ollama gpt-oss-20b) ran away on the large " + "overlapping every-turn payloads. Set to 1 for the old " + "every-turn crash-durability guarantee. Min 1. Cascade: " + "per-field merge (agent wins over default)."),
|
|
21854
|
-
overlap_turns: exports_external.number().int().min(0).optional().describe("Extra recent turns included in each chunked retain window on " + "top of `every_n_turns`, so window = overlap_turns + " + "every_n_turns recent turns. Vendor default is 2; switchroom's " + "scaffold default is 1 (smaller payloads for the local " + "reasoning consolidation model). Higher = more redundant " + "context re-sent per fire. Min 0. Cascade: per-field merge.")
|
|
21856
|
+
overlap_turns: exports_external.number().int().min(0).optional().describe("Extra recent turns included in each chunked retain window on " + "top of `every_n_turns`, so window = overlap_turns + " + "every_n_turns recent turns. Vendor default is 2; switchroom's " + "scaffold default is 1 (smaller payloads for the local " + "reasoning consolidation model). Higher = more redundant " + "context re-sent per fire. Min 0. Cascade: per-field merge."),
|
|
21857
|
+
tool_calls: exports_external.boolean().optional().describe("Whether auto-retain stores assistant tool_use blocks (with their " + "entire input dict) and tool_result content (up to 2000 chars) " + "alongside the human/assistant turns. Vendor + switchroom default " + "is true \u2014 the fleet behaves byte-identically until an operator " + "sets this false. Tool inputs/results are a large fraction of " + "retained volume (RFC memory-redesign P4) but also where evidence " + "lives (a commit SHA, a failing test's output, the diff that " + "fixed something), so the tradeoff is real and per-agent. false is " + "not a new mode: sidechains already force it off " + "(subagent_retain.py). Set false to drop tool exhaust from an " + "agent's retains. Cascade: per-field merge (agent wins over " + "default).")
|
|
21855
21858
|
}).optional().describe("Auto-retain (Stop-hook consolidation) cadence knobs")
|
|
21856
21859
|
}).optional();
|
|
21857
21860
|
HookEntrySchema = exports_external.object({
|
|
@@ -22239,6 +22242,7 @@ var init_schema = __esm(() => {
|
|
|
22239
22242
|
isolation: exports_external.enum(["default", "strict"]).optional(),
|
|
22240
22243
|
profile: exports_external.string().optional(),
|
|
22241
22244
|
directive_capture_nudge: exports_external.boolean().optional(),
|
|
22245
|
+
profile_capture_nudge: exports_external.boolean().optional(),
|
|
22242
22246
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
22243
22247
|
observation_scopes: ObservationScopesSchema,
|
|
22244
22248
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -22287,7 +22291,8 @@ var init_schema = __esm(() => {
|
|
|
22287
22291
|
}).optional(),
|
|
22288
22292
|
retain: exports_external.object({
|
|
22289
22293
|
every_n_turns: exports_external.number().int().min(1).optional(),
|
|
22290
|
-
overlap_turns: exports_external.number().int().min(0).optional()
|
|
22294
|
+
overlap_turns: exports_external.number().int().min(0).optional(),
|
|
22295
|
+
tool_calls: exports_external.boolean().optional()
|
|
22291
22296
|
}).optional(),
|
|
22292
22297
|
bank_mission: exports_external.string().optional(),
|
|
22293
22298
|
reflect_mission: exports_external.string().optional(),
|
|
@@ -105866,10 +105871,10 @@ function startOutboxSweep(deps) {
|
|
|
105866
105871
|
}
|
|
105867
105872
|
|
|
105868
105873
|
// ../src/build-info.ts
|
|
105869
|
-
var VERSION2 = "0.21.
|
|
105870
|
-
var COMMIT_SHA = "
|
|
105871
|
-
var COMMIT_DATE = "2026-08-
|
|
105872
|
-
var LATEST_PR =
|
|
105874
|
+
var VERSION2 = "0.21.16";
|
|
105875
|
+
var COMMIT_SHA = "d6c1267a";
|
|
105876
|
+
var COMMIT_DATE = "2026-08-17T09:16:43Z";
|
|
105877
|
+
var LATEST_PR = 4763;
|
|
105873
105878
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
105874
105879
|
|
|
105875
105880
|
// gateway/boot-version.ts
|