Pluggable memory backend
implement a second memory.Store and prove the existing harness doesn't know the difference.
Goal: implement a second memory.Store and prove the existing harness doesn't know the difference.
Difficulty: medium. Time: 1–2 hours. Touches: internal/memory/, main.go.
What's already in place
internal/memory/store.go defines the three-method Store interface — Save, Recall, Preamble. The default implementation, SessionFiles in internal/memory/sessionfiles.go, writes one markdown file per session under .harness/sessions/ and keeps a JSON index for fast lookups.
The interface is small on purpose. Substituting it is the test: do you understand the contract well enough to swap the storage without breaking the agent loop, the remember/recall tools, or the system-prompt preamble?
What to build
Pick one of these backends and implement it as a sibling of SessionFiles:
InMemoryRing{Capacity int}— a ring buffer that keeps the N most recent entries. No disk; resets on restart. Forces you to think about what Recall means without persistence.SQLite{Path string}— one row per Entry, with FTS5 for Recall. Forces a real schema decision and a query language choice.JSONBlob{Path string}— a single JSON file rewritten on each Save. The simplest persistent option; forces you to confront concurrent-write semantics.
Suggested steps
-
Create the file.
internal/memory/your_backend.go. Same package; same import surface asSessionFiles. -
Implement the three methods. Save returns
nilonce the entry is durable (for non-persistent stores, "durable" = in the slice). Recall does a best-effort search — substring match is acceptable; the interface doesn't promise semantic search. Preamble returns the always-loaded preface; usually built fromKindSessionSummaryentries. -
Write tests. A round-trip test for persistent backends (Save then Recall returns the entry). A capacity test for the ring buffer (the N+1-th Save evicts the oldest). Mirror
internal/memory/sessionfiles_test.go. -
Wire it in
main.go. Replace the line that constructsSessionFileswith your new backend, behind an env var or a flag if you want to support runtime selection. -
Verify the agent doesn't change.
remember "x",recall x, restart, and check the preamble. None of the existing code ininternal/agentorinternal/toolshould need touching.
Acceptance
- The
rememberandrecalltools work transparently against the new backend. - Existing tests in
internal/agent/andinternal/tool/pass without modification. - New tests in
internal/memory/your_backend_test.gocover the backend's specific behaviour (eviction, persistence, concurrency).
Stretch
- A
FanoutStoreadapter that writes to two stores at once (e.g., session files + sqlite for query). Demonstrates that the interface composes. - A migration command (
/memory migrate sqlite) that copies entries from one backend to another. - A bench: how slow is Recall when you have 10k entries? Use Go's
testing.Bto find out before you optimise.