commit 3e10988ccea555505bacf3beb3213e5fc4b1157e Author: Jerome Date: Sun Jun 28 19:23:52 2026 +0000 Improve memory audit contract: autonomous execution, incremental patches, pre-flight checks, stale state thresholds, dry-run mode, success metrics diff --git a/memory-audit-maintenance.prose.md b/memory-audit-maintenance.prose.md new file mode 100644 index 0000000..703f529 --- /dev/null +++ b/memory-audit-maintenance.prose.md @@ -0,0 +1,230 @@ +--- +name: memory-audit-maintenance +kind: responsibility +id: 067NC4KG01RG50R40M30E20918 +--- + +### Goal + +Autonomously audit and reorganize an agent's native memory (MEMORY.md, USER.md, SOUL.md), categorize entries, redistribute them to correct locations, verify live configurations, and free character budget all without user intervention unless a truly unresolvable ambiguity exists. + +### Requires + +(none this is a self-driven, autonomous node) + +### Maintains + +Memory health state current utilization, last audit timestamp, and any unresolved ambiguities. Postcondition: no entry is duplicated, no session note or stale snapshot survives, and no config is unverified. + +#### utilization +Current character utilization of MEMORY.md and USER.md. Material: the percentages. + +#### last_audit +Timestamp of the most recent successful audit. Material: the timestamp. + +#### unresolved +Any entries that could not be autonomously categorized. Material: the entry text and the reason for ambiguity. + +### Continuity + +- self-driven: re-audit every 14 days (2 weeks) +- input-driven: triggered by explicit user request ("memory audit", "memory maintenance", "clean up memory", "memory is full") +- threshold: trigger immediately if either store exceeds 85% utilization + +### Parameters + +- `memory_threshold`: percentage that triggers an immediate audit (default: 85) +- `max_memory_chars`: maximum allowed characters for MEMORY.md (default: 2200) +- `max_user_chars`: maximum allowed characters for USER.md (default: 1375) +- `compress_entries`: whether to rewrite entries for brevity (default: true) +- `dry_run`: whether to only report changes without applying them (default: false) + +### Strategies + +- **Autonomous first:** Never ask the user about entries that clearly belong in a deletion or move category. Only escalate on true ambiguity (e.g., an entry could be either a Preference or a Technical Config, and the choice affects which file it goes in). +- **Incremental over nuclear:** Always use patch-level edits (find-and-replace) rather than wholesale file rewrites. If the patch tool fails, fall back to rewrite only as a last resort. +- **Verify before trusting:** Every technical config in MEMORY.md must be verified against the live system. If a service is unreachable, mark it as `UNVERIFIED` rather than deleting it. +- **Stale state has a shelf life:** Any entry marked as "Temporary State" (e.g., "verbal offer", "deal pending", "negotiation phase") is deleted if older than 14 days. +- **Work around tool failures:** If the `memory` tool fails after 2 retries, add a summary marker and report the stale state in the unresolved list. + +### Invariants + +- No entry is deleted without being categorized first +- No duplicate entries survive across MEMORY.md and USER.md +- No session note or temporary state survives past 14 days +- No config is trusted without verification (or marked UNVERIFIED) + +### Execution + +```prose +# ============================================================ +# PHASE 1: Pre-flight +# ============================================================ + +# Verify the memory tool works +try: + memory_status = call check_memory_tool +catch: + memory_status = "BROKEN" + +# Read current state +memory_content = read_file("~/.hermes/memories/MEMORY.md") +user_content = read_file("~/.hermes/memories/USER.md") + +# Calculate current utilization +memory_util = len(memory_content) / max_memory_chars * 100 +user_util = len(user_content) / max_user_chars * 100 + +# Check if audit is needed +if last_audit > 14 days and memory_util < 75 and user_util < 75: + return {status: "SKIP", reason: "No audit needed"} + +# ============================================================ +# PHASE 2: Categorize every entry +# ============================================================ + +categorized = [] +for entry in split_entries(memory_content): + cat = call categorize_entry(entry) + categorized.append({entry, category: cat, source: "MEMORY.md"}) + +for entry in split_entries(user_content): + cat = call categorize_entry(entry) + categorized.append({entry, category: cat, source: "USER.md"}) + +# ============================================================ +# PHASE 3: Identify actions +# ============================================================ + +actions = [] +for item in categorized: + if item.category in ["Session Note", "Temporary State"]: + # Check age of temporary state + if item.category == "Temporary State" and item.age < 14 days: + continue # Too young to delete + actions.append({action: "DELETE", entry: item.entry, reason: item.category}) + elif item.category == "Historical Snapshot": + actions.append({action: "DELETE", entry: item.entry, reason: "Stale"}) + elif item.category == "Technical Config" and item.source == "USER.md": + actions.append({action: "MOVE", from: "USER.md", to: "MEMORY.md", entry: item.entry}) + elif item.category == "Identity" or item.category == "Preference" and item.source == "MEMORY.md": + actions.append({action: "MOVE", from: "MEMORY.md", to: "USER.md", entry: item.entry}) + elif item.category == "Operating Rule": + actions.append({action: "MOVE", from: "MEMORY.md", to: "Skill file", entry: item.entry}) + +# Check for duplicates +for entry_a, entry_b in find_duplicates(categorized): + actions.append({action: "DELETE", entry: entry_b.entry, reason: "Duplicate of " + entry_a.entry}) + +# ============================================================ +# PHASE 4: Verify live configs +# ============================================================ + +for item in categorized: + if item.category == "Technical Config" and item.entry contains URL: + result = call verify_endpoint(item.entry) + if result == "UNREACHABLE": + # Mark as UNVERIFIED, do not delete + actions.append({action: "MARK_UNVERIFIED", entry: item.entry}) + elif result == "VERIFIED": + pass # Good, nothing to do + +for item in categorized: + if item.category == "Technical Config" and item.entry contains "model:": + result = call verify_model(item.entry) + if result == "MISMATCH": + actions.append({action: "CORRECT", entry: item.entry, corrected: result.new_value}) + +# ============================================================ +# PHASE 5: Apply changes +# ============================================================ + +if dry_run: + return {status: "DRY_RUN", actions: actions, summary: generate_summary(actions)} + +# Apply deletions +for action in actions: + if action.action == "DELETE": + try: + memory action=remove target=action.source old_text=action.entry + catch after 2 retries: + patch path=action.source old_string=action.entry new_string="" + # Add summary marker since memory tool is broken + memory action=add target=action.source content="Entry deleted via patch: " + action.entry + +# Apply moves +for action in actions: + if action.action == "MOVE": + # Delete from source + patch path=action.from old_string=action.entry new_string="" + # Add to destination + append_file path=action.to content=action.entry + "\n" + +# Apply corrections +for action in actions: + if action.action == "CORRECT": + patch path="~/.hermes/memories/MEMORY.md" old_string=action.entry new_string=action.corrected + +# Apply UNVERIFIED marks +for action in actions: + if action.action == "MARK_UNVERIFIED": + patch path="~/.hermes/memories/MEMORY.md" old_string=action.entry new_string=action.entry + " [UNVERIFIED]" + +# ============================================================ +# PHASE 6: Post-audit verification +# ============================================================ + +new_memory_content = read_file("~/.hermes/memories/MEMORY.md") +new_user_content = read_file("~/.hermes/memories/USER.md") + +new_memory_util = len(new_memory_content) / max_memory_chars * 100 +new_user_util = len(new_user_content) / max_user_chars * 100 + +# Add summary markers to in-memory stores +memory action=add target=memory content="MEMORY.md rewritten. Utilization: " + new_memory_util + "%." +memory action=add target=user content="USER.md rewritten. Utilization: " + new_user_util + "%." + +# ============================================================ +# PHASE 7: Report +# ============================================================ + +return { + status: "COMPLETE", + memory_utilization: new_memory_util, + user_utilization: new_user_util, + actions_applied: len(actions), + deletions: count(actions, "DELETE"), + moves: count(actions, "MOVE"), + corrections: count(actions, "CORRECT"), + unverified: count(actions, "MARK_UNVERIFIED"), + unresolved: unresolved_entries, + last_audit: now(), + summary: generate_summary(actions) +} +``` + +### Shape + +- `self`: categorize, verify configs, apply incremental patches, generate reports +- `delegates`: + - `categorize_entry`: determine the category of a memory entry + - `check_memory_tool`: verify the memory tool is functional + - `verify_endpoint`: check if a URL is reachable + - `verify_model`: check if a model config matches live config.yaml + - `find_duplicates`: detect duplicate entries across files + - `generate_summary`: produce a human-readable summary of actions + +### Tools + +- `file:read`: read MEMORY.md and USER.md +- `file:patch`: incremental edits via find-and-replace +- `file:append`: append entries when moving between files +- `memory:action`: add/remove/replace entries in the in-memory store +- `network:curl`: verify endpoint reachability +- `cli:grep`: verify model configs against config.yaml + +### Environment + +- `MEMORY_PATH`: ~/.hermes/memories/MEMORY.md +- `USER_PATH`: ~/.hermes/memories/USER.md +- `CONFIG_PATH`: ~/.hermes/config.yaml \ No newline at end of file