Skip to content

feat(memory,skills): approve/deny gate for memory + skill writes#38199

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-2d0a2eb3
Jun 10, 2026
Merged

feat(memory,skills): approve/deny gate for memory + skill writes#38199
teknium1 merged 1 commit into
mainfrom
hermes/hermes-2d0a2eb3

Conversation

@teknium1

@teknium1 teknium1 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Memory and skill writes can now be gated per-subsystem with a tri-state write_mode — including writes the background self-improvement review fork makes on its own (the source of the unprompted "wrong assumption" saves users reported).

Default is on (current behaviour — writes flow freely), so existing installs are unaffected until a user opts in.

How it works

Both memory.write_mode and skills.write_mode accept:

  • on — write freely (default)
  • off — never write; the tool returns a clean "disabled" result
  • approve — don't commit; route the write for review
    • memory + foreground: inline approve/deny prompt (entries are small enough to show in a chat bubble)
    • memory + background-review: staged for review (a daemon thread can't block on a prompt)
    • skills (any origin): always staged — a SKILL.md is too large to eyeball inline

Pending writes persist under <HERMES_HOME>/pending/{memory,skills}/<id>.json (survive restarts) and are reviewed via slash commands:

  • /memory [pending|approve <id>|reject <id>|mode <on|off|approve>] — works on CLI and every gateway platform
  • /skills [pending|approve <id>|reject <id>|diff <id>|mode <...>]diff shows the full skill diff (CLI/dashboard/file), never crammed into a chat bubble

Changes

  • tools/write_approval.py (new): gate decision + file-backed pending store; reuses the existing dangerous-command approval machinery for inline prompts and the skill-provenance ContextVar for foreground/background origin.
  • hermes_cli/write_approval_commands.py (new): shared pending-review handlers (list/approve/reject/diff/mode) used by both CLI and gateway.
  • tools/memory_tool.py, tools/skill_manager_tool.py: evaluate the gate before mutating; apply_*_pending replay paths bypass the gate (skills via a ContextVar) for approved writes.
  • hermes_cli/commands.py: register /memory and the new /skills review subcommands.
  • hermes_cli/cli_commands_mixin.py, gateway/slash_commands.py: CLI + gateway handlers.
  • hermes_cli/config.py: memory.write_mode / skills.write_mode defaults (on) with documenting comments.
  • website/docs/user-guide/features/memory.md: document the gate.

Validation

Result
tests/tools/test_write_approval.py 18 passed (new)
tests/hermes_cli/test_commands.py 144 passed
E2E (isolated HERMES_HOME) default-on passes through; off blocks; approve stages + pending CRUD roundtrips
CI full 6-shard matrix green

Infographic

memory-skill-write-gate

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-2d0a2eb3 vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 10648 on HEAD, 10629 on base (🆕 +19)

🆕 New issues (11):

Rule Count
unsupported-operator 5
invalid-argument-type 2
unresolved-attribute 2
not-subscriptable 1
unresolved-import 1
First entries
tests/tools/test_write_approval.py:232: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["Invalid mode"]` and `str | None`
tests/tools/test_write_approval.py:159: [invalid-argument-type] invalid-argument-type: Argument to function `skill_pending_diff` is incorrect: Expected `dict[str, Any]`, found `dict[str, Any] | None`
tests/tools/test_write_approval.py:211: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["Rejected"]` and `str | None`
gateway/slash_commands.py:1984: [unresolved-attribute] unresolved-attribute: Object of type `Self@_handle_memory_command` has no attribute `_evict_cached_agent`
tests/tools/test_write_approval.py:187: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["No pending memory"]` and `str | None`
tests/tools/test_write_approval.py:200: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["Approved 2"]` and `str | None`
tests/tools/test_write_approval.py:173: [not-subscriptable] not-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
gateway/slash_commands.py:1972: [unresolved-attribute] unresolved-attribute: Object of type `Self@_handle_memory_command` has no attribute `_session_key_for_source`
tests/tools/test_write_approval.py:224: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["approve"]` and `str | None`
tools/skill_manager_tool.py:888: [invalid-argument-type] invalid-argument-type: Argument to function `skill_manage` is incorrect: Expected `str`, found `Any | None`
tests/tools/test_write_approval.py:14: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`

✅ Fixed issues: none

Unchanged: 5567 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@alt-glitch alt-glitch added type/feature New feature or request comp/cli CLI entry point, hermes_cli/, setup wizard tool/memory Memory tool and memory providers tool/skills Skills system (list, view, manage) P3 Low — cosmetic, nice to have labels Jun 3, 2026
@teknium1 teknium1 force-pushed the hermes/hermes-2d0a2eb3 branch from dd0c623 to bab8356 Compare June 9, 2026 16:52
@teknium1 teknium1 closed this Jun 9, 2026
@teknium1 teknium1 reopened this Jun 9, 2026
Adds memory.write_mode and skills.write_mode (on|off|approve), applied to
both foreground turns and the background self-improvement review fork — the
source of the unprompted 'wrong assumption' saves users reported.

- on (default): write freely, unchanged behaviour
- off: never write; the tool returns a clean disabled result
- approve: don't commit. Memory foreground writes prompt inline (small,
  reviewable in a chat bubble); background memory writes and ALL skill writes
  stage to a pending store instead (a SKILL.md is too large to review inline,
  and a daemon thread can't block on a prompt)

Review staged writes from CLI or any messaging platform:
  /memory pending|approve|reject|mode
  /skills pending|approve|reject|diff|mode

Skill review respects the size asymmetry: inline you see a one-line gist;
the full unified diff stays out-of-band (/skills diff, dashboard, or the
staged JSON file).

New: tools/write_approval.py (gate + pending store), hermes_cli/
write_approval_commands.py (shared CLI+gateway handlers). Gates wired at the
single entry points memory_tool() and skill_manage(), using the existing
write-origin ContextVar to distinguish foreground from background_review.
@teknium1 teknium1 force-pushed the hermes/hermes-2d0a2eb3 branch from bab8356 to 8064417 Compare June 10, 2026 04:39
@teknium1 teknium1 merged commit 96af61b into main Jun 10, 2026
24 checks passed
@teknium1 teknium1 deleted the hermes/hermes-2d0a2eb3 branch June 10, 2026 04:51
teknium1 added a commit that referenced this pull request Jun 10, 2026
…ing, and gateway /skills review (#43452)

Follow-ups to #38199/#43354 found in post-merge review:

- Inline CLI memory approval never worked: the per-thread approval callback
  was not passed to prompt_dangerous_approval, so the prompt_toolkit
  fail-closed guard (#15216) denied every gated foreground write without
  showing a prompt. Now invokes the registered callback directly; a crashed
  prompt falls back to staging instead of a silent deny.
- Gateway sessions claimed inline support but prompt_dangerous_approval has
  no gateway round-trip (that lives in the pending-approval queue), so gated
  gateway memory writes hit the input() fallback and denied. Gateway
  contexts now stage for /memory pending review.
- /skills pending|approve|reject|diff|approval now works on the gateway
  (gateway_config_gate on skills.write_approval), so skills staged from a
  messaging session can be reviewed there. Diff output truncated for chat.
- memory_tool validates required params before the gate so invalid writes
  are rejected immediately instead of staged and failing at approve time.
- Stale tri-state write_mode docstrings updated to the boolean gate; docs
  table corrected (inline prompt is interactive-CLI-only).
- 6 new tests covering the interactive approve/deny/error paths, gateway
  staging, skills never-prompt invariant, and pre-gate validation.
changman pushed a commit to changman/hermes-agent that referenced this pull request Jun 10, 2026
…sResearch#38199)

Adds memory.write_mode and skills.write_mode (on|off|approve), applied to
both foreground turns and the background self-improvement review fork — the
source of the unprompted 'wrong assumption' saves users reported.

- on (default): write freely, unchanged behaviour
- off: never write; the tool returns a clean disabled result
- approve: don't commit. Memory foreground writes prompt inline (small,
  reviewable in a chat bubble); background memory writes and ALL skill writes
  stage to a pending store instead (a SKILL.md is too large to review inline,
  and a daemon thread can't block on a prompt)

Review staged writes from CLI or any messaging platform:
  /memory pending|approve|reject|mode
  /skills pending|approve|reject|diff|mode

Skill review respects the size asymmetry: inline you see a one-line gist;
the full unified diff stays out-of-band (/skills diff, dashboard, or the
staged JSON file).

New: tools/write_approval.py (gate + pending store), hermes_cli/
write_approval_commands.py (shared CLI+gateway handlers). Gates wired at the
single entry points memory_tool() and skill_manage(), using the existing
write-origin ContextVar to distinguish foreground from background_review.
changman pushed a commit to changman/hermes-agent that referenced this pull request Jun 10, 2026
…ing, and gateway /skills review (NousResearch#43452)

Follow-ups to NousResearch#38199/NousResearch#43354 found in post-merge review:

- Inline CLI memory approval never worked: the per-thread approval callback
  was not passed to prompt_dangerous_approval, so the prompt_toolkit
  fail-closed guard (NousResearch#15216) denied every gated foreground write without
  showing a prompt. Now invokes the registered callback directly; a crashed
  prompt falls back to staging instead of a silent deny.
- Gateway sessions claimed inline support but prompt_dangerous_approval has
  no gateway round-trip (that lives in the pending-approval queue), so gated
  gateway memory writes hit the input() fallback and denied. Gateway
  contexts now stage for /memory pending review.
- /skills pending|approve|reject|diff|approval now works on the gateway
  (gateway_config_gate on skills.write_approval), so skills staged from a
  messaging session can be reviewed there. Diff output truncated for chat.
- memory_tool validates required params before the gate so invalid writes
  are rejected immediately instead of staged and failing at approve time.
- Stale tri-state write_mode docstrings updated to the boolean gate; docs
  table corrected (inline prompt is interactive-CLI-only).
- 6 new tests covering the interactive approve/deny/error paths, gateway
  staging, skills never-prompt invariant, and pre-gate validation.
teknium1 added a commit that referenced this pull request Jun 11, 2026
…slash-command docs (#43801)

The memory/skill write-approval gate (#38199, #43354, #43452) was only
documented inside features/memory.md. Surface it everywhere users will
actually look:

- features/skills.md: new 'Gating agent skill writes' section under
  skill_manage, with the staging semantics, review commands, and the
  distinction from skills.guard_agent_created
- configuration.md: memory.write_approval added to the Memory
  Configuration block; new 'Write approval for skill writes' subsection
  next to the guard_agent_created scanner
- reference/slash-commands.md: /memory and /skills review subcommands in
  both the CLI and messaging tables; Notes updated since /skills
  pending/approve/reject/diff/approval now works on the gateway
- features/memory.md: cross-link to the new skills section
alt-glitch pushed a commit that referenced this pull request Jun 14, 2026
)

Adds memory.write_mode and skills.write_mode (on|off|approve), applied to
both foreground turns and the background self-improvement review fork — the
source of the unprompted 'wrong assumption' saves users reported.

- on (default): write freely, unchanged behaviour
- off: never write; the tool returns a clean disabled result
- approve: don't commit. Memory foreground writes prompt inline (small,
  reviewable in a chat bubble); background memory writes and ALL skill writes
  stage to a pending store instead (a SKILL.md is too large to review inline,
  and a daemon thread can't block on a prompt)

Review staged writes from CLI or any messaging platform:
  /memory pending|approve|reject|mode
  /skills pending|approve|reject|diff|mode

Skill review respects the size asymmetry: inline you see a one-line gist;
the full unified diff stays out-of-band (/skills diff, dashboard, or the
staged JSON file).

New: tools/write_approval.py (gate + pending store), hermes_cli/
write_approval_commands.py (shared CLI+gateway handlers). Gates wired at the
single entry points memory_tool() and skill_manage(), using the existing
write-origin ContextVar to distinguish foreground from background_review.
alt-glitch pushed a commit that referenced this pull request Jun 14, 2026
…ing, and gateway /skills review (#43452)

Follow-ups to #38199/#43354 found in post-merge review:

- Inline CLI memory approval never worked: the per-thread approval callback
  was not passed to prompt_dangerous_approval, so the prompt_toolkit
  fail-closed guard (#15216) denied every gated foreground write without
  showing a prompt. Now invokes the registered callback directly; a crashed
  prompt falls back to staging instead of a silent deny.
- Gateway sessions claimed inline support but prompt_dangerous_approval has
  no gateway round-trip (that lives in the pending-approval queue), so gated
  gateway memory writes hit the input() fallback and denied. Gateway
  contexts now stage for /memory pending review.
- /skills pending|approve|reject|diff|approval now works on the gateway
  (gateway_config_gate on skills.write_approval), so skills staged from a
  messaging session can be reviewed there. Diff output truncated for chat.
- memory_tool validates required params before the gate so invalid writes
  are rejected immediately instead of staged and failing at approve time.
- Stale tri-state write_mode docstrings updated to the boolean gate; docs
  table corrected (inline prompt is interactive-CLI-only).
- 6 new tests covering the interactive approve/deny/error paths, gateway
  staging, skills never-prompt invariant, and pre-gate validation.
alt-glitch pushed a commit that referenced this pull request Jun 14, 2026
…slash-command docs (#43801)

The memory/skill write-approval gate (#38199, #43354, #43452) was only
documented inside features/memory.md. Surface it everywhere users will
actually look:

- features/skills.md: new 'Gating agent skill writes' section under
  skill_manage, with the staging semantics, review commands, and the
  distinction from skills.guard_agent_created
- configuration.md: memory.write_approval added to the Memory
  Configuration block; new 'Write approval for skill writes' subsection
  next to the guard_agent_created scanner
- reference/slash-commands.md: /memory and /skills review subcommands in
  both the CLI and messaging tables; Notes updated since /skills
  pending/approve/reject/diff/approval now works on the gateway
- features/memory.md: cross-link to the new skills section
AIalliAI pushed a commit to AIalliAI/Hermes that referenced this pull request Jun 14, 2026
…slash-command docs (NousResearch#43801)

The memory/skill write-approval gate (NousResearch#38199, NousResearch#43354, NousResearch#43452) was only
documented inside features/memory.md. Surface it everywhere users will
actually look:

- features/skills.md: new 'Gating agent skill writes' section under
  skill_manage, with the staging semantics, review commands, and the
  distinction from skills.guard_agent_created
- configuration.md: memory.write_approval added to the Memory
  Configuration block; new 'Write approval for skill writes' subsection
  next to the guard_agent_created scanner
- reference/slash-commands.md: /memory and /skills review subcommands in
  both the CLI and messaging tables; Notes updated since /skills
  pending/approve/reject/diff/approval now works on the gateway
- features/memory.md: cross-link to the new skills section
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have tool/memory Memory tool and memory providers tool/skills Skills system (list, view, manage) type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants