v3: Add ledger, drift detection, canary checks, per-agent privacy, writer registry
This commit is contained in:
@@ -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
|
||||||
Reference in New Issue
Block a user