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
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SessionStart hook — Memory v2 M1 rules-block tamper sentinel
|
|
3
|
+
# (carve-M1.md §3, red-team-M1.md §B/§C, MINOR fixes #6/#7).
|
|
4
|
+
#
|
|
5
|
+
# Recomputes the rules block's sha256 sentinel + the mutation-log hash
|
|
6
|
+
# chain and compares against what's embedded in the agent's own
|
|
7
|
+
# CLAUDE.md. Purely advisory in M1 (dark build — no `memory.rules_block`
|
|
8
|
+
# agent exists live yet): this hook exists so the wiring, the read-only
|
|
9
|
+
# discipline, and the fast no-op path are all proven out and tested
|
|
10
|
+
# BEFORE M3 flips the flag on any real agent.
|
|
11
|
+
#
|
|
12
|
+
# STRICT DISCIPLINE (red-team §C, root-owned-overlay EACCES hazard):
|
|
13
|
+
# - READ-ONLY. This script must NEVER write to the agent's tree. A
|
|
14
|
+
# root-invoked write here would leave a root-owned file behind and
|
|
15
|
+
# EACCES the agent's own subsequent writes to it (the exact failure
|
|
16
|
+
# class that dropped clerk's crons for weeks — see this repo's
|
|
17
|
+
# CLAUDE.md "root-tier host access" section). `switchroom memory
|
|
18
|
+
# rule verify` (the CLI path) is the only writer-adjacent tool, and
|
|
19
|
+
# even IT never writes — verify is read-only too.
|
|
20
|
+
# - Prints to STDOUT, not stderr. SessionStart hook stdout is added to
|
|
21
|
+
# the model's context (unlike PreCompact); a stderr message would be
|
|
22
|
+
# silently dropped by Claude Code's hook contract, defeating the
|
|
23
|
+
# entire point of a tamper *sentinel* — see this file's own header
|
|
24
|
+
# precedent in bin/timezone-hook.sh for the additionalContext
|
|
25
|
+
# mechanism this hook reuses (NOT because "no additionalContext
|
|
26
|
+
# emitter exists" — one already does, in timezone-hook.sh and
|
|
27
|
+
# scaffold.ts; this hook simply needs the same JSON shape).
|
|
28
|
+
# - No-ops FAST and SILENTLY when the rules-block markers are absent
|
|
29
|
+
# (the M1/M3-flag-off dark case, and the pre-first-rule case even
|
|
30
|
+
# with the flag on) — never print a divergence notice about a block
|
|
31
|
+
# that was never created.
|
|
32
|
+
#
|
|
33
|
+
# Wiring note (MINOR fix #7): unlike working-state-reload-hook.sh
|
|
34
|
+
# (matcher: "compact" — fires ONLY on compaction), this hook is wired
|
|
35
|
+
# with NO matcher, so it fires on every SessionStart source (startup,
|
|
36
|
+
# resume, clear, fork, compact). That is a deliberate divergence: a
|
|
37
|
+
# tamper sentinel that only checked itself after compaction would miss
|
|
38
|
+
# tampering that happened between a fresh boot and the first compaction
|
|
39
|
+
# (the common case for a short-lived session). The check itself is a
|
|
40
|
+
# single local file read + a hash compare — cheap enough to run on every
|
|
41
|
+
# boot without a latency concern (contrast working-state-reload's
|
|
42
|
+
# network-hop briefing, which specifically justified restricting itself
|
|
43
|
+
# to the compact matcher).
|
|
44
|
+
#
|
|
45
|
+
# Exit code: 0 always. A hook that exits non-zero BLOCKS the turn in
|
|
46
|
+
# Claude Code; a tamper signal must degrade to a visible notice, never
|
|
47
|
+
# a hard stop (the same "failure modes are silent" doctrine as
|
|
48
|
+
# timezone-hook.sh).
|
|
49
|
+
|
|
50
|
+
set -u
|
|
51
|
+
|
|
52
|
+
CLAUDE_MD="${CLAUDE_PROJECT_DIR:-}/CLAUDE.md"
|
|
53
|
+
|
|
54
|
+
if [ -z "${CLAUDE_PROJECT_DIR:-}" ] || [ ! -f "$CLAUDE_MD" ]; then
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Fast no-op: markers absent (dark build / no rules yet). grep -q is a
|
|
59
|
+
# single pass over the file, no subshell fork per line.
|
|
60
|
+
if ! grep -q '<!-- switchroom:rules:begin -->' "$CLAUDE_MD" 2>/dev/null; then
|
|
61
|
+
exit 0
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Delegate the actual sentinel recompute to the CLI verb this module
|
|
65
|
+
# already ships (`switchroom memory rule verify <agent>`), which reuses
|
|
66
|
+
# rules-store.ts's verifyIntegrity — one recompute implementation, not
|
|
67
|
+
# two (a bash reimplementation of the sha256-over-canonical-JSON
|
|
68
|
+
# encoding would be a second place for the two encodings to drift).
|
|
69
|
+
# `switchroom` is expected on PATH inside the agent container image;
|
|
70
|
+
# if it's missing, degrade silently rather than error the turn.
|
|
71
|
+
if ! command -v switchroom >/dev/null 2>&1; then
|
|
72
|
+
exit 0
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
AGENT_NAME="$(basename "${CLAUDE_PROJECT_DIR:-}")"
|
|
76
|
+
VERIFY_OUT="$(switchroom memory rule verify "$AGENT_NAME" 2>&1)"
|
|
77
|
+
VERIFY_EXIT=$?
|
|
78
|
+
|
|
79
|
+
# Exit-code contract (memory-rules.ts `verify`):
|
|
80
|
+
# 0 = clean; 2 = GENUINE TAMPER; any other non-zero = an ENVIRONMENT
|
|
81
|
+
# failure (config unreadable, agent-dir mismatch, withConfigError exit 1,
|
|
82
|
+
# `switchroom` bug). Only code 2 warrants injecting a tamper notice into
|
|
83
|
+
# the model's context — an environment failure that hard-injected "tamper
|
|
84
|
+
# FAILED" would cry wolf on every broken boot and erode the signal. Degrade
|
|
85
|
+
# silently on everything that is not an unambiguous tamper.
|
|
86
|
+
if [ "$VERIFY_EXIT" -ne 2 ]; then
|
|
87
|
+
exit 0
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
MSG="Rules-block tamper sentinel FAILED for \"$AGENT_NAME\": ${VERIFY_OUT}"
|
|
91
|
+
|
|
92
|
+
if command -v jq >/dev/null 2>&1; then
|
|
93
|
+
jq -cn --arg msg "$MSG" \
|
|
94
|
+
'{hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:$msg}}'
|
|
95
|
+
else
|
|
96
|
+
ESCAPED=${MSG//\\/\\\\}
|
|
97
|
+
ESCAPED=${ESCAPED//\"/\\\"}
|
|
98
|
+
printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"%s"}}\n' "$ESCAPED"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
exit 0
|
|
@@ -11118,12 +11118,14 @@ var AgentMemorySchema = exports_external.object({
|
|
|
11118
11118
|
}
|
|
11119
11119
|
}).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)."),
|
|
11120
11120
|
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."),
|
|
11121
|
+
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)."),
|
|
11121
11122
|
disposition: exports_external.object({
|
|
11122
11123
|
skepticism: exports_external.number().int().min(1).max(5).optional().describe("How much the bank doubts unverified claims (1-5; engine default 3)."),
|
|
11123
11124
|
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)."),
|
|
11124
11125
|
empathy: exports_external.number().int().min(1).max(5).optional().describe("How much the bank weights emotional/relational context (1-5; engine default 3).")
|
|
11125
11126
|
}).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`)."),
|
|
11126
11127
|
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)."),
|
|
11128
|
+
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)."),
|
|
11127
11129
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
11128
11130
|
observation_scopes: ObservationScopesSchema,
|
|
11129
11131
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -11172,7 +11174,8 @@ var AgentMemorySchema = exports_external.object({
|
|
|
11172
11174
|
}).optional().describe("Auto-recall tuning knobs"),
|
|
11173
11175
|
retain: exports_external.object({
|
|
11174
11176
|
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)."),
|
|
11175
|
-
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.")
|
|
11177
|
+
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."),
|
|
11178
|
+
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).")
|
|
11176
11179
|
}).optional().describe("Auto-retain (Stop-hook consolidation) cadence knobs")
|
|
11177
11180
|
}).optional();
|
|
11178
11181
|
var HookEntrySchema = exports_external.object({
|
|
@@ -11560,6 +11563,7 @@ var profileFields = {
|
|
|
11560
11563
|
isolation: exports_external.enum(["default", "strict"]).optional(),
|
|
11561
11564
|
profile: exports_external.string().optional(),
|
|
11562
11565
|
directive_capture_nudge: exports_external.boolean().optional(),
|
|
11566
|
+
profile_capture_nudge: exports_external.boolean().optional(),
|
|
11563
11567
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
11564
11568
|
observation_scopes: ObservationScopesSchema,
|
|
11565
11569
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -11608,7 +11612,8 @@ var profileFields = {
|
|
|
11608
11612
|
}).optional(),
|
|
11609
11613
|
retain: exports_external.object({
|
|
11610
11614
|
every_n_turns: exports_external.number().int().min(1).optional(),
|
|
11611
|
-
overlap_turns: exports_external.number().int().min(0).optional()
|
|
11615
|
+
overlap_turns: exports_external.number().int().min(0).optional(),
|
|
11616
|
+
tool_calls: exports_external.boolean().optional()
|
|
11612
11617
|
}).optional(),
|
|
11613
11618
|
bank_mission: exports_external.string().optional(),
|
|
11614
11619
|
reflect_mission: exports_external.string().optional(),
|
|
@@ -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(),
|
|
@@ -11879,12 +11879,14 @@ var AgentMemorySchema = exports_external.object({
|
|
|
11879
11879
|
}
|
|
11880
11880
|
}).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)."),
|
|
11881
11881
|
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."),
|
|
11882
|
+
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)."),
|
|
11882
11883
|
disposition: exports_external.object({
|
|
11883
11884
|
skepticism: exports_external.number().int().min(1).max(5).optional().describe("How much the bank doubts unverified claims (1-5; engine default 3)."),
|
|
11884
11885
|
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)."),
|
|
11885
11886
|
empathy: exports_external.number().int().min(1).max(5).optional().describe("How much the bank weights emotional/relational context (1-5; engine default 3).")
|
|
11886
11887
|
}).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`)."),
|
|
11887
11888
|
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)."),
|
|
11889
|
+
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)."),
|
|
11888
11890
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
11889
11891
|
observation_scopes: ObservationScopesSchema,
|
|
11890
11892
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -11933,7 +11935,8 @@ var AgentMemorySchema = exports_external.object({
|
|
|
11933
11935
|
}).optional().describe("Auto-recall tuning knobs"),
|
|
11934
11936
|
retain: exports_external.object({
|
|
11935
11937
|
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)."),
|
|
11936
|
-
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.")
|
|
11938
|
+
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."),
|
|
11939
|
+
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).")
|
|
11937
11940
|
}).optional().describe("Auto-retain (Stop-hook consolidation) cadence knobs")
|
|
11938
11941
|
}).optional();
|
|
11939
11942
|
var HookEntrySchema = exports_external.object({
|
|
@@ -12321,6 +12324,7 @@ var profileFields = {
|
|
|
12321
12324
|
isolation: exports_external.enum(["default", "strict"]).optional(),
|
|
12322
12325
|
profile: exports_external.string().optional(),
|
|
12323
12326
|
directive_capture_nudge: exports_external.boolean().optional(),
|
|
12327
|
+
profile_capture_nudge: exports_external.boolean().optional(),
|
|
12324
12328
|
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
12325
12329
|
observation_scopes: ObservationScopesSchema,
|
|
12326
12330
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
@@ -12369,7 +12373,8 @@ var profileFields = {
|
|
|
12369
12373
|
}).optional(),
|
|
12370
12374
|
retain: exports_external.object({
|
|
12371
12375
|
every_n_turns: exports_external.number().int().min(1).optional(),
|
|
12372
|
-
overlap_turns: exports_external.number().int().min(0).optional()
|
|
12376
|
+
overlap_turns: exports_external.number().int().min(0).optional(),
|
|
12377
|
+
tool_calls: exports_external.boolean().optional()
|
|
12373
12378
|
}).optional(),
|
|
12374
12379
|
bank_mission: exports_external.string().optional(),
|
|
12375
12380
|
reflect_mission: exports_external.string().optional(),
|