--- 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