// Package pathway implements Mem0-style versioned trace memory per // ADR-004. Pathway memory is an append-only event log of opaque // traces with Add / Update / Revise / Retire / History / Search // operations. Persisted via JSONL (one event per line) with // corruption recovery on load. // // Why this exists: agents need to remember what they tried and // what worked. Mem0 is the lowest-common-denominator memory // substrate; building on its surface means agent loops written // against any Mem0-aware library work here. See feedback_meta_ // index_vision.md for the north-star learning-loop framing. package pathway import ( "encoding/json" "errors" ) // Trace is one entry in pathway memory. Content is opaque to the // substrate — callers store whatever JSON shape they want; this // layer just preserves and indexes it. type Trace struct { UID string `json:"uid"` Content json.RawMessage `json:"content"` PredecessorUID string `json:"predecessor_uid,omitempty"` CreatedAtNs int64 `json:"created_at_ns"` UpdatedAtNs int64 `json:"updated_at_ns"` Retired bool `json:"retired"` ReplayCount int `json:"replay_count"` Tags []string `json:"tags,omitempty"` } // op is the wire-format kind tag for JSONL persistence. Internal // to the package — operations exposed publicly are method calls // on Store; the JSONL form is its own concern. type op string const ( opAdd op = "add" opUpdate op = "update" opRevise op = "revise" opRetire op = "retire" opReplay op = "replay" ) // event is one line of the JSONL log. Trace is included for ops // that introduce or replace a trace; UID alone suffices for retire // and replay; Content alone suffices for update (reuses the // existing trace's UID via the UID field). type event struct { Op op `json:"op"` Trace *Trace `json:"trace,omitempty"` UID string `json:"uid,omitempty"` Content json.RawMessage `json:"content,omitempty"` } // Errors surfaced to callers. Sentinel-based so HTTP handlers (when // cmd/pathwayd lands) can map to status codes via errors.Is. var ( ErrNotFound = errors.New("pathway: trace not found") ErrAlreadyExists = errors.New("pathway: trace already exists") ErrPredecessorMissing = errors.New("pathway: predecessor trace missing") ErrCycle = errors.New("pathway: history cycle detected") ErrEmptyUID = errors.New("pathway: empty uid") ErrInvalidContent = errors.New("pathway: invalid content") ) // SearchFilter narrows a Search to matching traces. Empty filter // returns everything (excluding retired; flip IncludeRetired to // override). All set fields are AND-combined. type SearchFilter struct { // Tag returns traces whose Tags slice contains this string. Tag string // ContentContains returns traces whose Content contains this // substring (treats Content as raw bytes; caller's contract // for whether that's meaningful). ContentContains string // CreatedAfterNs returns traces with CreatedAtNs >= this value. CreatedAfterNs int64 // CreatedBeforeNs returns traces with CreatedAtNs <= this value. // Zero = no upper bound. CreatedBeforeNs int64 // IncludeRetired flips the default "exclude retired" behavior. IncludeRetired bool }