1
0

feat: heartbeat memory hooks — pre-recall and post-update

Wire MEMORY.md + soul.md into the thinking loop so each heartbeat
is grounded in identity and recent context, breaking repetitive loops.

Pre-hook: _load_memory_context() reads hot memory first (changes each
cycle) then soul.md (stable identity), truncated to 1500 chars.

Post-hook: _update_memory() writes a "Last Reflection" section to
MEMORY.md after each thought so the next cycle has fresh context.

soul.md is read-only from the heartbeat — never modified by it.
All hooks degrade gracefully and never crash the heartbeat.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trip T
2026-03-11 20:54:13 -04:00
parent ea2dbdb4b5
commit 6a7875e05f
3 changed files with 233 additions and 0 deletions

View File

@@ -21,6 +21,7 @@ logger = logging.getLogger(__name__)
PROJECT_ROOT = Path(__file__).parent.parent.parent
HOT_MEMORY_PATH = PROJECT_ROOT / "MEMORY.md"
VAULT_PATH = PROJECT_ROOT / "memory"
SOUL_PATH = VAULT_PATH / "self" / "soul.md"
HANDOFF_PATH = VAULT_PATH / "notes" / "last-session-handoff.md"
@@ -433,6 +434,15 @@ class MemorySystem:
return "\n".join(summary_parts) if summary_parts else ""
def read_soul(self) -> str:
"""Read soul.md — Timmy's core identity. Returns empty string if missing."""
try:
if SOUL_PATH.exists():
return SOUL_PATH.read_text()
except Exception as exc:
logger.debug("Failed to read soul.md: %s", exc)
return ""
def get_system_context(self) -> str:
"""Get full context for system prompt injection.