Compare commits
2
Commits
94b3bf84b4
...
e0d98d684a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0d98d684a | ||
|
|
3e10988cce |
+213
-188
@@ -1,205 +1,230 @@
|
|||||||
---
|
---
|
||||||
kind: responsibility
|
|
||||||
name: memory-audit-maintenance
|
name: memory-audit-maintenance
|
||||||
description: >
|
kind: responsibility
|
||||||
Systematic audit and reorganization of an agent's native memory (MEMORY.md,
|
id: 067NC4KG01RG50R40M30E20918
|
||||||
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").
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 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:**
|
(none this is a self-driven, autonomous node)
|
||||||
- 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
|
|
||||||
|
|
||||||
**How to run (via OpenProse CLI):**
|
### Maintains
|
||||||
```bash
|
|
||||||
# Default — 85% threshold, verify configs, compress entries
|
|
||||||
prose run memory-audit-maintenance
|
|
||||||
|
|
||||||
# Softer audit — only flag issues, don't rewrite files
|
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.
|
||||||
prose run memory-audit-maintenance compress_entries=false
|
|
||||||
|
|
||||||
# Hard audit — stricter limits
|
#### utilization
|
||||||
prose run memory-audit-maintenance memory_threshold=90 max_memory_chars=800 max_user_chars=300
|
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`
|
### Tools
|
||||||
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, 800–1,100 chars max
|
|
||||||
5. **Rewrite USER.md** — identity + preferences only, 300–500 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
|
|
||||||
|
|
||||||
## 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
|
### Environment
|
||||||
- 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)
|
|
||||||
|
|
||||||
## Parameters
|
- `MEMORY_PATH`: ~/.hermes/memories/MEMORY.md
|
||||||
|
- `USER_PATH`: ~/.hermes/memories/USER.md
|
||||||
- memory_threshold: number — Usage % that triggers audit (default: 85, max: 95)
|
- `CONFIG_PATH`: ~/.hermes/config.yaml
|
||||||
- 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% | ✅ |
|
|
||||||
```
|
|
||||||
Reference in New Issue
Block a user