Compare commits

..
2 Commits
+213 -188
View File
@@ -1,205 +1,230 @@
---
kind: responsibility
name: memory-audit-maintenance
description: >
Systematic audit and reorganization of an agent's native memory (MEMORY.md,
USER.md, SOUL.md). Categorizes entries, redistributes to correct homes,
verifies live configs, and frees up char budget. Run when memory usage
exceeds 85% or on explicit user request ("memory audit", "memory maintenance").
kind: responsibility
id: 067NC4KG01RG50R40M30E20918
---
## Quickstart — How to Run This Contract
### Goal
### For the Agent Running This Contract
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.
Read this section first. It tells you exactly what to do.
### Requires
**When to run:**
- User says: `"memory audit"`, `"memory maintenance"`, `"clean up memory"`, `"memory is full"`
- You detect that your `memory` store usage exceeds 85% in a write attempt
- It's been 2+ weeks since the last audit
(none this is a self-driven, autonomous node)
**How to run (via OpenProse CLI):**
```bash
# Default — 85% threshold, verify configs, compress entries
prose run memory-audit-maintenance
### Maintains
# Softer audit — only flag issues, don't rewrite files
prose run memory-audit-maintenance compress_entries=false
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.
# Hard audit — stricter limits
prose run memory-audit-maintenance memory_threshold=90 max_memory_chars=800 max_user_chars=300
#### 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)
}
```
### How to Follow the Template (Manual)
### Shape
If `prose` CLI is not available:
- `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
1. **Read both memory files:** `cat ~/.hermes/memories/MEMORY.md` and `cat ~/.hermes/memories/USER.md`
2. **Check in-memory usage:** Use the `memory` tool with no args
3. **Categorize every entry** using the Categorization Guide below
4. **Rewrite MEMORY.md** — technical configs only, 8001,100 chars max
5. **Rewrite USER.md** — identity + preferences only, 300500 chars max
6. **Verify live configs** — curl each endpoint, check each model
7. **Sync in-memory** — Add summary markers (or just leave file as source of truth)
8. **Report** using the Example Output template at the bottom
### Tools
## Maintains
- `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
- last_audit: timestamp — When the last full audit was completed
- memory_usage_pct: number — Current memory store usage percentage
- user_usage_pct: number — Current user store usage percentage
- total_entries_categorized: number — How many entries were audited
- entries_moved: number — How many entries changed location
- entries_deleted: number — How many stale entries were removed
- live_configs_verified: array — Which configs were verified against live systems
- known_issues: array — Problems found during audit (stale keys, dead services)
### Environment
## Parameters
- memory_threshold: number — Usage % that triggers audit (default: 85, max: 95)
- verify_configs: boolean — Whether to live-check configs after audit (default: true)
- compress_entries: boolean — Whether to shorten verbose entries (default: true)
- remove_session_notes: boolean — Strip "currently doing X" markers (default: true)
- max_memory_chars: number — Target max chars for MEMORY.md after audit (default: 1100)
- max_user_chars: number — Target max chars for USER.md after audit (default: 500)
## Continuity
The audit cycle is **event-driven**, not just cron-based:
- **On threshold breach**: If memory usage exceeds `memory_threshold`, wake immediately
- **On user request**: `"memory audit"`, `"memory maintenance"`, `"clean up memory"` — explicit trigger
- **Retrospective**: Every 2-4 weeks if no other trigger fired — check for gradual bloat
- **On config change**: After major provider swaps or infrastructure migrations, verify live configs
- **On new agent onboarding**: Run once as part of initialization to establish clean baseline
## Success Criteria (What Makes a Memory Audit "Good")
The audit is considered COMPLETE when ALL of these pass:
### Inventory Complete
- MEMORY.md content read and categorized
- USER.md content read and categorized
- In-memory `memory` and `user` store usage percentages recorded
- Every entry tagged with: `Infrastructure | Identity | Preference | Operating Rule | Historical | Session Note`
### Redistribution Correct
- Identity entries → USER.md
- Preference entries → USER.md
- Technical config entries → MEMORY.md
- Operating rules → Skill file or SOUL.md
- Historical snapshots (dated checkpoints) → Deleted
- Session notes ("currently doing X") → Deleted
### Files Compact
- MEMORY.md ≤ `max_memory_chars` chars
- USER.md ≤ `max_user_chars` chars
- No duplicate information across files
- No frustration signals or verbose descriptions
- § separator between entries (standard convention)
### Configs Verified
- API keys confirmed in `.env` file (grep, not read)
- Model names in memory match live `config.yaml`
- Endpoints in memory respond to curl/health checks
- Credential pairs (username/token, email/password) match deployed state
- Any mismatch corrected in memory with ✅/❌ labels
### In-Memory Synced
- Summary marker added to `memory` store: "MEMORY.md rewritten <date>. Holds only tech configs."
- Summary marker added to `user` store: "Home channel: <channel>. USER.md rewritten <date>."
- Usage confirmed dropped below 60% after sync
### Skill Created/Updated (if applicable)
- Operating rules that belong in a skill → created via `skill_manage`
- Existing skills verified not to conflict with memory content
- Skill category appropriate and description searchable
## Remembers
Each audit stores:
- Entry categorization decisions (why X went to USER instead of MEMORY)
- What was deleted (stale snapshots, session notes)
- What was verified (configs that passed live checks)
- What failed verification (configs that need user attention)
- Known tool quirks (memory replace/remove failures)
- Compression patterns used (how verbose entries were shortened)
## Audit Rules
### Rule 1: Read Before Delete
Never delete an entry without first reading it and categorizing it. Show the user a summary of what will change if unsure about a categorization.
### Rule 2: Categories Are Mutual Exclusive
Each entry belongs to exactly ONE category:
- **Identity** — "Jerome, Florida, Telegram @mejerome19"
- **Preference** — "Single-account first for AWS"
- **Technical Config** — "SearXNG on storepve:8888"
- **Operating Rule** — "Never go rogue on infrastructure"
- **Historical Snapshot** — "Baseline v30 from Jun 26" (DELETE)
- **Session Note** — "Currently performing memory audit" (DELETE)
### Rule 3: Rules Belong in Skills
If an entry is a procedure, protocol, or mandate (`"do X this way"`, `"never do Y"`) — it belongs in a skill file, not MEMORY.md. Check `skills_list` first; create via `skill_manage` if no match exists.
### Rule 4: Verify Live Before Trusting Memory
Every config entry in MEMORY.md must be verified against the live system:
- Model name → `grep config.yaml`
- API key → `grep .env`
- Service URL → `curl` health check
- Credentials → cross-reference with deployed state
### Rule 5: Work Around the `memory` Tool
The `memory` tool's `remove` and `replace` actions use strict text matching that can fail on special characters. If a remove/replace fails repeatedly:
- Do not retry more than 2 times
- Add a new summary marker entry instead
- Report to user: "File on disk updated; in-memory store has stale leftovers"
- The file on disk (MEMORY.md, USER.md) is the source of truth regardless
### Rule 6: Report Before Asking
Don't ask the user "should I delete X?" for session notes or historical snapshots — those are always safe to delete. Only ask about ambiguous categorizations or cross-file moves of preference data.
## Execution
1. **Read state** — Read MEMORY.md, USER.md, check in-memory usage via `memory` tool
2. **Categorize** — Tag every entry with its category
3. **Prepare rewrites** — Draft compressed MEMORY.md and USER.md:
- MEMORY.md: Technical configs only (800-1100 chars)
- USER.md: Identity + preferences only (300-500 chars)
4. **Write files** — Overwrite MEMORY.md and USER.md
5. **Verify live configs** — Check every config entry against actual system state
6. **Sync in-memory** — Add summary markers to `memory` and `user` stores
7. **Create/update skills** — Move operating rules to skill files if needed
8. **Report** — Output clean status table with before/after/verification
## Example Output
```
## Memory Audit Complete ✅
| File | Before | After | Reduction |
|---|---|---|---|
| MEMORY.md | 1,653 chars | 1,077 chars | ~35% |
| USER.md | 860 chars | 418 chars | ~51% |
### What Moved
| Entry | From | To |
|---|---|---|
| Identity + Preferences | MEMORY.md | USER.md |
| Agent boundary rule | MEMORY.md | SOUL.md (persona) |
| Baseline v30 snapshot | MEMORY.md | Deleted |
### Config Verification
| Config | Live Check | Status |
|---|---|---|
| DeepSeek model | config.yaml: deepseek-chat | ✅ |
| DeepSeek key | .env found | ✅ |
| SearXNG endpoint | :8888 curl 200 | ✅ |
### Memory Usage
| Store | Before | After | Status |
|---|---|---|---|
| memory | 91% | 59% | ✅ |
| user | 85% | 41% | ✅ |
```
- `MEMORY_PATH`: ~/.hermes/memories/MEMORY.md
- `USER_PATH`: ~/.hermes/memories/USER.md
- `CONFIG_PATH`: ~/.hermes/config.yaml