Skip to content

feat(agent): governed persistence funnel — stage-or-deny via pre_persist_write - #2

Merged
ElystrumCore merged 3 commits into
mainfrom
agent/verified-persistence
Jul 20, 2026
Merged

feat(agent): governed persistence funnel — stage-or-deny via pre_persist_write#2
ElystrumCore merged 3 commits into
mainfrom
agent/verified-persistence

Conversation

@ElystrumCore

Copy link
Copy Markdown
Owner

Summary

Companion to agent-lineage PR NousResearch#20 (verified persistence). All runtime memory/skill writes now route through one funnel — agent/persist_boundary.py::governed_persist — which invokes the pre_persist_write REQUIRED hook: allow+staged → content quarantined, canonical path untouched; block → clean caller error; hook machinery unavailable → decision-less local staging (grants nothing). The real write sites (tools/memory_tool.py::MemoryStore._write_file, tools/skill_manager_tool.py::_atomic_write_text — learning mutations ride the former) are refactored through it; no runtime SOUL.md writer exists (documented; kind="soul" future-proofed). hermes_cli/plugins.py: pre_persist_write valid required hook + typed digest/staged directive passthrough. Fail-closed hardening from review: malformed enforcer allow (missing/non-bool staged) stages locally when an enforcer is registered (fail-SAFE presence check); AST-based write-site regression pin (RED-verified by plant, open() mode read from args[1]).

Pre-cutover behavior is byte-identical (no enforcer registered → passthrough). Deployment to the governed install is a separate explicit cutover.

Verification

  • Opus review (2 rounds): funnel completeness verified by independent reachability trace — no live-agent/curator-reachable bypass writes canonical content; both Importants fixed and re-verified.
  • 37 persist-boundary tests + 134 enforcer/plugins tests green (WSL); refactored-module batch green modulo pre-existing environment flakes.

🤖 Generated with Claude Code

CN-CLI and others added 3 commits July 20, 2026 01:06
…sist_write

New agent/persist_boundary.py::governed_persist(kind, path, content, meta) is
the single chokepoint for runtime writes to Hermes' canonical memory/skill/
SOUL.md paths: it invokes the pre_persist_write REQUIRED hook (mirroring how
cron/scheduler.py and hermes_cli/kanban_db.py invoke pre_run_start), and is
the ONLY place that performs the actual disk write -- refactored call sites
never touch a canonical path themselves.

- allow+staged -> content quarantined governed-side; canonical path untouched.
- block -> PersistResult(denied=True); call sites raise PersistDenied, the
  same clean-error contract a failed write already had.
- bare allow (no persistence enforcer registered yet -- the pre-cutover
  default, mirroring the pre_run_start precedent) -> governed_persist
  performs the original atomic write itself, unchanged.
- hook unreachable or an unrecognized directive -> decision-less local stage
  under $HERMES_HOME/persist-quarantine-local/<sha256hex>/, warned, grants
  nothing.

hermes_cli/plugins.py: registers pre_persist_write as a valid required-hook
boundary (VALID_HOOKS + register_required_hook's allowed set) and generalizes
invoke_required_hook's context pass-through (previously run_id/session_id
only) to also carry digest/staged, so a pre_persist_write directive's payload
survives the hook aggregation.

tools/memory_tool.py::MemoryStore._write_file and
tools/skill_manager_tool.py::_atomic_write_text now route through
governed_persist (kind="memory" / kind="skill" respectively);
agent/learning_mutations.py shares the memory site's _write_file and is
covered automatically. SOUL.md: recon found only bootstrap/default-creation
writers and the dashboard's human-editor endpoint -- no runtime SOUL.md
writer exists in this fork today; kind="soul" is implemented and tested for
a future writer.

Tests: tests/agent/test_persist_boundary.py covers the funnel's directive
handling, the hook-unreachable local stage, both refactored write sites
(deny/stage/passthrough/kind-mapping), and an AST-scoped source-scan pin
asserting no canonical write primitive survives outside the funnel module.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ElystrumCore
ElystrumCore merged commit 9c05d42 into main Jul 20, 2026
@cursor

cursor Bot commented Jul 20, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant