Author: Mani Saint-Victor, MD / bionicbutterfly13
hermes-memory-policy-gate is a MemSkill-inspired memory policy gate for Hermes Agent.
It does not store memory. It decides where a proposed memory write should go and returns an auditable decision.
GitHub-installable plugin with narrow returned-block enforcement for session_search_only and user-memory boundary attempts, Phase 4 live-write-interception planning/harness coverage, and a Phase 5 non-writing caller contract for the built-in memory_tool surface.
The current enforcement contract blocks attempted durable-memory writes for ephemeral task progress when callers explicitly request non-dry-run evaluation. It also blocks attempts to force stale PR, issue, phase, or completed-task logs into user_memory. Durable user preferences, Mnemosyne global/session candidates, skill patches, project artifacts, and clean-field approval gates remain advisory and non-writing. Phase 4 adds mapped Hermes write entrypoints and evaluator scenarios for live-write intent without wiring any live interceptor. Phase 5 selects only tools.memory_tool.memory_tool and defines caller-side behavior for blocked=true, approval_required=true, and advisory passthrough without editing Hermes core.
This plugin does not mutate Hermes core, credentials, providers, gateway, config, Mnemosyne, skills, or existing memory.
This project is MemSkill-inspired, not MemSkill-dependent.
The plugin keeps dependencies = [] so it remains lightweight and GitHub-installable. MemSkill may become an optional backend later, behind the same auditable decision schema, after the plugin API and offline evaluator stabilize.
Install from GitHub:
hermes plugins install bionicbutterfly13/hermes-memory-policy-gate
hermes plugins enable hermes-memory-policy-gateRestart the gateway only if using it from gateway surfaces:
hermes gateway restartPyPI publishing is phase 2. This repository is PyPI-ready, but GitHub plugin installation is the primary distribution path until the plugin API and evaluator stabilize.
Allowed routing tiers:
no_write_clean_field_boundaryuser_memorymnemosyne_globalmnemosyne_sessionskill_patchproject_artifactsession_search_onlysuperseded_updatenoisy_memory_invalidation
When enabled as a Hermes plugin, it registers the tool:
memory_policy_gate
The tool accepts text/context/source/metadata and returns a JSON decision.
PYTHONPATH=src python3 -m hermes_memory_policy_gate scenarios/memory_routing_cases.json --jsonThe seed scenarios include non-dry-run returned-block cases and Phase 4 live-write-intent harness cases, so dry_run_only=false is expected; live_writes=false must remain true.
Phase 4 mapped Hermes write entrypoints without changing Hermes core:
- built-in curated memory:
tools/memory_tool.py::memory_toolandMemoryStorewrite methods - provider/Mnemosyne-style paths:
MemoryManager.sync_all,on_session_end,on_pre_compress,on_memory_write, and provider hooks - procedural memory:
tools/skill_manager_tool.pycreate/edit/patch/delete/supporting-file paths - project artifacts:
tools/file_tools.py::write_file_toolandpatch_tool - transcript recall:
tools/session_search_tool.py::session_searchas the read-only route for ephemeral task progress
Details are in docs/phase4-live-write-entrypoints.md.
Phase 5 chooses one write surface only: the built-in curated memory tool.
from hermes_memory_policy_gate import plan_memory_tool_call
plan = plan_memory_tool_call({
"action": "add",
"target": "user",
"content": "Remember that I submitted PR #123 and completed Phase 4 today.",
})The returned MemoryToolCallerPlan is non-writing:
blocked=true->caller_action=block_original_memory_write,call_original=falseapproval_required=true->caller_action=require_explicit_approval,call_original=false- advisory decision ->
caller_action=advisory_passthrough,call_original=true
Details are in docs/phase5-memory-tool-caller-contract.md.
PYTHONPATH=src python3 -m compileall -q src tests __init__.py
PYTHONPATH=src python3 -m unittest discover -s testsOptional after installing dev extras:
PYTHONPATH=src python3 -m pytest tests -qThis is an evaluator and router. It is not a writer.
session_search_only decisions can enforce a no-write block when dry_run=false; user-memory boundary attempts can return block_user_memory_write when stale task-progress content is being forced into user_memory. Phase 4 live-write-intent scenarios still report would_mutate=false and evaluator live_writes=false. Phase 5 adds a non-writing memory_tool caller plan that tells a future interceptor whether to block, hold for approval, or pass through; it does not wire that interceptor. Every tier other than the returned-block cases remains advisory/dry-run until a future explicitly approved integration phase wires decisions into live Hermes write paths.