refactor(memory,skills): replace tri-state write_mode with boolean write_approval (default off) (#43354)

The shipped tri-state write_mode (on|off|approve) conflated two concepts —
whether writes are enabled and whether they're gated — so 'on' (writes flow
freely, gate inactive) read like 'gating is on'. Replace it with a single
clear boolean gate that defaults off.

  memory.write_approval / skills.write_approval:
    false (default) — write freely; the approval gate is off (pre-gate behaviour)
    true            — require approval: memory foreground prompts inline, memory
                      background-review + all skill writes stage for review

The old 'off = block all writes' mode is dropped; memory_enabled: false already
disables memory entirely, so a third 'block' state was redundant.

- tools/write_approval.py: get_write_mode/MODE_* → write_approval_enabled() bool;
  evaluate_gate() loses the config-driven 'blocked' path (blocked now only comes
  from an interactive user denial).
- tools/memory_tool.py, tools/skill_manager_tool.py: comment + behaviour follow.
- hermes_cli/config.py: memory/skills write_mode → write_approval (False);
  _config_version 28→29 with a 28→29 migration that renames any persisted
  write_mode (approve→true, on/off/unset→false) and drops the old key.
- slash commands: '/memory|/skills mode <on|off|approve>' → 'approval <on|off>'
  ('mode' kept as a back-compat alias); set_mode_fn callback now takes a bool.
- write_approval_commands.py, cli_commands_mixin.py, gateway/slash_commands.py,
  commands.py: handlers + registry args/subcommands updated.
- docs + tests rewritten for the boolean model; added migration tests.
This commit is contained in:
Teknium 2026-06-09 23:21:14 -07:00 committed by GitHub
parent 9ca9697342
commit 095f526b11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 296 additions and 187 deletions

View file

@ -681,8 +681,8 @@ def memory_tool(
if target not in {"memory", "user"}:
return tool_error(f"Invalid target '{target}'. Use 'memory' or 'user'.", success=False)
# Write gate: off blocks the write; approve stages it (background) or
# prompts inline (foreground). on (default) passes straight through.
# Approval gate: when on, stages the write (background) or prompts inline
# (foreground); when off (default) passes straight through.
gate_result = _apply_write_gate(action, target, content, old_text)
if gate_result is not None:
return gate_result