v3: Add ledger, drift detection, canary checks, per-agent privacy, writer registry

This commit is contained in:
Jerome
2026-06-29 00:42:54 +00:00
parent e0d98d684a
commit 9ac383e812
+102 -9
View File
@@ -6,7 +6,7 @@ id: 067NC4KG01RG50R40M30E20918
### Goal ### 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. 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. Every agent runs this contract for **its own** memory files only no cross-agent access, no shared state.
### Requires ### Requires
@@ -14,7 +14,7 @@ Autonomously audit and reorganize an agent's native memory (MEMORY.md, USER.md,
### Maintains ### 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. Memory health state current utilization, last audit timestamp, drift alerts, and any unresolved ambiguities. Postcondition: no entry is duplicated, no session note or stale snapshot survives, no config is unverified, and the audit ledger is up-to-date.
#### utilization #### utilization
Current character utilization of MEMORY.md and USER.md. Material: the percentages. Current character utilization of MEMORY.md and USER.md. Material: the percentages.
@@ -25,6 +25,12 @@ Timestamp of the most recent successful audit. Material: the timestamp.
#### unresolved #### unresolved
Any entries that could not be autonomously categorized. Material: the entry text and the reason for ambiguity. Any entries that could not be autonomously categorized. Material: the entry text and the reason for ambiguity.
#### drift_alerts
Active alerts from drift detection (e.g., deletions accelerating, unverified configs growing). Material: the alert list.
#### ledger
Persistent audit trail stored at `~/.hermes/memories/MEMORY_AUDIT_LEDGER.md`. Material: append-only, never modified or deleted.
### Continuity ### Continuity
- self-driven: re-audit every 14 days (2 weeks) - self-driven: re-audit every 14 days (2 weeks)
@@ -41,11 +47,12 @@ Any entries that could not be autonomously categorized. Material: the entry text
### Strategies ### 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). - **Autonomous first:** Never ask the user about entries that clearly belong in a deletion or move category. Only escalate on true ambiguity.
- **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. - **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. - **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. - **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. - **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.
- **Privacy isolation:** Each agent only reads and writes its own memory files. No cross-agent memory access, no shared ledger, no shared state. The contract is the standard; each agent runs it independently.
### Invariants ### Invariants
@@ -53,14 +60,43 @@ Any entries that could not be autonomously categorized. Material: the entry text
- No duplicate entries survive across MEMORY.md and USER.md - No duplicate entries survive across MEMORY.md and USER.md
- No session note or temporary state survives past 14 days - No session note or temporary state survives past 14 days
- No config is trusted without verification (or marked UNVERIFIED) - No config is trusted without verification (or marked UNVERIFIED)
- The audit ledger is append-only never modified or deleted
- The canary entry survives every audit unmodified
### Execution ### Execution
```prose ```prose
# ============================================================ # ============================================================
# PHASE 1: Pre-flight # PHASE 0: Canaries & Privacy
# ============================================================ # ============================================================
# Check canaries if either is missing or modified, raise CRITICAL alert
memory_canary = read_file_line("~/.hermes/memories/MEMORY.md", containing="CANARY: Do not modify this line")
user_canary = read_file_line("~/.hermes/memories/USER.md", containing="CANARY: Do not modify this line")
if memory_canary is null or user_canary is null:
return {
status: "CRITICAL",
alert: "CANARY BREACH memory integrity compromised",
details: {
memory_canary_intact: memory_canary is not null,
user_canary_intact: user_canary is not null
}
}
# This agent only touches its own files no cross-agent access
# Confirm we are operating on this agent's own memory directory
if not directory_exists("~/.hermes/memories"):
return {status: "ERROR", reason: "Memory directory not found for this agent"}
# ============================================================
# PHASE 1: Pre-flight & Ledger
# ============================================================
# Read the audit ledger for drift detection
ledger = read_file("~/.hermes/memories/MEMORY_AUDIT_LEDGER.md")
last_audit_entry = parse_last_entry(ledger)
# Verify the memory tool works # Verify the memory tool works
try: try:
memory_status = call check_memory_tool memory_status = call check_memory_tool
@@ -76,9 +112,36 @@ memory_util = len(memory_content) / max_memory_chars * 100
user_util = len(user_content) / max_user_chars * 100 user_util = len(user_content) / max_user_chars * 100
# Check if audit is needed # Check if audit is needed
if last_audit > 14 days and memory_util < 75 and user_util < 75: if last_audit_entry.timestamp > 14 days and memory_util < 75 and user_util < 75:
return {status: "SKIP", reason: "No audit needed"} return {status: "SKIP", reason: "No audit needed"}
# ============================================================
# PHASE 1b: Drift Detection (Compare to Last Audit)
# ============================================================
drift_alerts = []
if last_audit_entry exists:
# Deletions accelerating? (50% increase from last audit)
if last_audit_entry.deletions > 0:
deletion_increase = (memory_util - last_audit_entry.memory_util_after) / last_audit_entry.deletions * 100
if deletion_increase > 50:
drift_alerts.append("ALERT: Memory bloat accelerating deletions increasing by " + deletion_increase + "% vs last audit")
# Unverified configs growing?
if last_audit_entry.unverified > 0:
unverified_increase = count_entries(memory_content, "[UNVERIFIED]") - last_audit_entry.unverified
if unverified_increase > 2:
drift_alerts.append("ALERT: Unverified configs growing " + unverified_increase + " new unverified entries since last audit")
# Audit missed? (No audit for >21 days)
if last_audit_entry.timestamp > 21 days:
drift_alerts.append("ALERT: Audit gap no audit completed in 21+ days")
# Utilization not improving? (After audit, still >70%)
if last_audit_entry.memory_util_after > 70:
drift_alerts.append("ALERT: Previous audit failed to reduce MEMORY.md below 70% capacity issue")
# ============================================================ # ============================================================
# PHASE 2: Categorize every entry # PHASE 2: Categorize every entry
# ============================================================ # ============================================================
@@ -140,7 +203,7 @@ for item in categorized:
# ============================================================ # ============================================================
if dry_run: if dry_run:
return {status: "DRY_RUN", actions: actions, summary: generate_summary(actions)} return {status: "DRY_RUN", actions: actions, drift_alerts: drift_alerts, summary: generate_summary(actions)}
# Apply deletions # Apply deletions
for action in actions: for action in actions:
@@ -180,12 +243,39 @@ new_user_content = read_file("~/.hermes/memories/USER.md")
new_memory_util = len(new_memory_content) / max_memory_chars * 100 new_memory_util = len(new_memory_content) / max_memory_chars * 100
new_user_util = len(new_user_content) / max_user_chars * 100 new_user_util = len(new_user_content) / max_user_chars * 100
# Verify canaries survived the audit
post_canary_check = read_file_line("~/.hermes/memories/MEMORY.md", containing="CANARY: Do not modify this line")
if post_canary_check is null:
drift_alerts.append("CRITICAL: Canary destroyed during audit memory integrity compromised")
# Add summary markers to in-memory stores # Add summary markers to in-memory stores
memory action=add target=memory content="MEMORY.md rewritten. Utilization: " + new_memory_util + "%." 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 + "%." memory action=add target=user content="USER.md rewritten. Utilization: " + new_user_util + "%."
# ============================================================ # ============================================================
# PHASE 7: Report # PHASE 7: Append to Ledger
# ============================================================
ledger_entry = """
## """ + now() + """
- memory_util_before: """ + memory_util + """%
- memory_util_after: """ + new_memory_util + """%
- user_util_before: """ + user_util + """%
- user_util_after: """ + new_user_util + """%
- deletions: """ + count(actions, "DELETE") + """
- moves: """ + count(actions, "MOVE") + """
- corrections: """ + count(actions, "CORRECT") + """
- unverified: """ + count(actions, "MARK_UNVERIFIED") + """
- unresolved: """ + len(unresolved_entries) + """
- drift_alerts: """ + len(drift_alerts) + """
- canary_intact: """ + (post_canary_check is not null) + """
- status: COMPLETE
"""
append_file path="~/.hermes/memories/MEMORY_AUDIT_LEDGER.md" content=ledger_entry
# ============================================================
# PHASE 8: Report
# ============================================================ # ============================================================
return { return {
@@ -198,14 +288,16 @@ return {
corrections: count(actions, "CORRECT"), corrections: count(actions, "CORRECT"),
unverified: count(actions, "MARK_UNVERIFIED"), unverified: count(actions, "MARK_UNVERIFIED"),
unresolved: unresolved_entries, unresolved: unresolved_entries,
drift_alerts: drift_alerts,
last_audit: now(), last_audit: now(),
ledger_updated: true,
summary: generate_summary(actions) summary: generate_summary(actions)
} }
``` ```
### Shape ### Shape
- `self`: categorize, verify configs, apply incremental patches, generate reports - `self`: categorize, verify configs, apply incremental patches, generate reports, drift detection, ledger management, canary checks
- `delegates`: - `delegates`:
- `categorize_entry`: determine the category of a memory entry - `categorize_entry`: determine the category of a memory entry
- `check_memory_tool`: verify the memory tool is functional - `check_memory_tool`: verify the memory tool is functional
@@ -227,4 +319,5 @@ return {
- `MEMORY_PATH`: ~/.hermes/memories/MEMORY.md - `MEMORY_PATH`: ~/.hermes/memories/MEMORY.md
- `USER_PATH`: ~/.hermes/memories/USER.md - `USER_PATH`: ~/.hermes/memories/USER.md
- `CONFIG_PATH`: ~/.hermes/config.yaml - `CONFIG_PATH`: ~/.hermes/config.yaml
- `LEDGER_PATH`: ~/.hermes/memories/MEMORY_AUDIT_LEDGER.md