Documentation
¶
Overview ¶
capture_rate.go — process-scoped memory capture-rate tracker.
Design: a single global CaptureRateTracker holds a ring buffer of timestamps for the last N successful chunk writes (up to 120 slots, well beyond any 60-second window) so ChunksPerMinute can be computed exactly without a background goroutine.
Thread-safety: all mutations go through a sync.Mutex. The ring buffer is small enough that the lock is never contended for more than a few microseconds.
Embedder health is tracked via two atomic values:
- lastEmbedLatencyNs: the nanosecond duration of the most recent embedder call (set by RecordEmbedCall).
- a small ring buffer of recent error timestamps (last 5 min window).
No migrations: all state is in-process memory; it resets on restart.
Long-term memory types. Chunk is the unit the user pins via the chat surface's "remember this" button; the embedding stays out of the JSON wire shape because the frontend never reads it (it is consumed only by the local k-NN search inside core/memory.Store).
Package memory — embedder eligibility check.
EmbedderEligibility walks a slice of ProviderProfile records (same logic as newEmbedderFromProfiles in core/rpc/api.go) but READ-ONLY: it collects metadata about which profiles are eligible and which kinds are present but skipped, without constructing an Embedder.
Eligible kinds (OpenAI-compatible /v1/embeddings shape):
openai, openrouter, custom_openai_compatible, azure
Skipped kinds (no embeddings endpoint or different wire shape):
anthropic — no /v1/embeddings endpoint bedrock — AWS Titan uses a different wire shape; deferred
OpenAI-compatible embedder. We mirror core/llm/anthropic's net/http shape (no SDK dependency) so dependency surface stays unchanged.
Package memory — health snapshot computation for the inspector surface.
HealthSnapshot is populated by indexed COUNT passes over the in-RAM chunk slice held by the store; there is no SQL or full-table scan. The Store is gob-backed, so "indexed" means a single slice walk with O(n) complexity — still well within the 200 ms p95 budget for a 100 k-chunk store on modern hardware.
Package memory — retrieval history ring buffer (§2.1 active-session retrieval inspector, memory-inspection-ui-01KX5R8E WP02).
The retriever pushes a RetrievalRecord after every successful call; the RPC surface reads the most recent record for a session to power the "Last turn retrieval" inspector panel.
Design constraints:
- Bounded: per-session cap 200, global cap 10k (oldest entry pruned first).
- Process-scoped singleton via GlobalRetrievalHistory(); never persisted.
- Concurrency-safe: single RWMutex guards all state.
Cross-session retrieval glue. The Retriever wraps Store + Embedder behind a single small surface the LLM impl can call without taking a hard dependency on either concrete type. The opt-in gate is read per-call via the EnabledFn so toggling memory in settings takes effect on the next send without restarting the harness.
Long-term memory vector store. The Store interface lets the rpc layer treat the persistence and the in-RAM index as a single seam; the default implementation is a gob-encoded snapshot with a flat cosine-similarity scan.
Why a flat scan instead of an external vector DB: the design notes called for chromem-go (pure-Go, file-backed). The harness build environment cannot fetch new module proxies, so we ship an in-house equivalent with the same on-disk + interface contract. Swapping in a chromem-go-backed implementation later is a one-file change because every caller goes through Store.
Privacy posture: the file is created mode 0600. The embedding column is JSON-omitted (`json:"-"`) so when a future export path round-trips chunks through JSON, the user's vector representations stay local.
Index ¶
- Constants
- Variables
- func HashContent(content string) string
- type ActivityWindow
- type CaptureRateSnapshot
- type CaptureRateTracker
- type Chunk
- type ChunkCounts
- type Embedder
- type EmbedderEligibility
- type EmbedderInfo
- type Extractor
- type GateSetter
- type HealthSnapshot
- type HealthSnapshotter
- type KeyResolver
- type MemoryWriteGate
- type NoopEmbedder
- type OpenAIEmbedder
- type OpenAIOption
- type ProfileEligibilityInput
- type PruneCapable
- type Result
- type RetrievalHistory
- type RetrievalRecord
- type RetrievalResult
- type Retriever
- type ScopeFilter
- type ScopePromoter
- type Snapshot
- type Snippet
- type Store
- type View
Constants ¶
const ( ScopeKindGlobal = "global" ScopeKindProject = "project" ScopeKindSession = "session" // ScopeKindLongTerm is the long-term scope tier added by the narrative // layer (memory-narrative-layer-01KQ8TD1 WP09). Chunks promoted to // long_term resist the prune sweep and are loaded into the system-prompt // prelude at session start. One-way promotion: demotion requires an // explicit pruner verdict, not a score drop. ScopeKindLongTerm = "long_term" )
Scope kinds. Mirrors claude-mem's scope dimension: a chunk is either global (visible across every session), project-scoped (visible to every session inside a Project), or session-scoped (the default — visible only to the originating session).
const ( // HistoryPerSessionCap is the maximum number of RetrievalRecord entries // kept per session-ID key in the ring buffer. HistoryPerSessionCap = 200 // HistoryGlobalCap is the hard upper bound on total RetrievalRecord rows // across all sessions. When reached, the oldest entry (by any session) is // evicted before the new one is inserted. HistoryGlobalCap = 10_000 )
const DedupWindow = 30 * time.Second
DedupWindow is the look-back window inside which an Add with a matching ContentHash + scope is rejected as a duplicate. Mirrors claude-mem's behaviour: the same content can be re-pinned later.
Variables ¶
var ErrDuplicate = errors.New("memory: duplicate chunk within dedup window")
ErrDuplicate is returned by Add when a chunk with the same scope + content hash was added inside DedupWindow.
ErrEmbedderUnavailable is returned when the harness has no working embedder configured. Surfaces in the rpc layer as a typed error so the UI can render "configure an OpenAI provider to enable memory".
Functions ¶
func HashContent ¶
HashContent returns the hex-encoded sha256 of content. Used by the store to compute ContentHash on Add when the caller leaves it empty and to backfill old gobs that predate the column.
Types ¶
type ActivityWindow ¶
type ActivityWindow struct {
// Captured is the number of chunks created in the last 7 days.
Captured int
// Pruned is always 0 at snapshot time — the prune sweep removes rows;
// we cannot reconstruct the pre-prune count without a journal.
// Reserved for a future audit-journal integration.
Pruned int
// Promoted is the number of chunks promoted to "global" scope in the
// last 7 days (CreatedAt used as a proxy because promotion uses
// move semantics — it deletes + re-inserts with a fresh CreatedAt).
Promoted int
}
ActivityWindow summarises chunk activity over the last 7 days.
type CaptureRateSnapshot ¶
type CaptureRateSnapshot struct {
ChunksPerMinute float64 // writes in the last 60s
EmbedderHealth string // "ok" | "slow" | "error"
LastErrorAt *time.Time // nil when no recent error
RecentErrorCount int // errors in the last embedErrorWindow
}
CaptureRateSnapshot is the computed snapshot returned to the RPC surface.
type CaptureRateTracker ¶
type CaptureRateTracker struct {
// contains filtered or unexported fields
}
CaptureRateTracker tracks memory capture velocity and embedder health. The zero value is ready to use.
func GlobalCaptureTracker ¶
func GlobalCaptureTracker() *CaptureRateTracker
GlobalCaptureTracker returns the process-scoped capture rate tracker. The pointer is stable for the process lifetime.
func (*CaptureRateTracker) RecordEmbedCall ¶
func (t *CaptureRateTracker) RecordEmbedCall(d time.Duration)
RecordEmbedCall records the latency of one embedder call. Call this after every Embed() invocation regardless of success.
func (*CaptureRateTracker) RecordEmbedError ¶
func (t *CaptureRateTracker) RecordEmbedError(at time.Time)
RecordEmbedError records one embedder error at the given time.
func (*CaptureRateTracker) RecordWrite ¶
func (t *CaptureRateTracker) RecordWrite(at time.Time)
RecordWrite records one successful chunk write at the given time. Call this immediately after Store.Add returns nil.
func (*CaptureRateTracker) Snapshot ¶
func (t *CaptureRateTracker) Snapshot(now time.Time) CaptureRateSnapshot
Snapshot computes the current capture-rate snapshot. now is injected so callers can pass time.Now().UTC() in production and a fixed time in tests.
type Chunk ¶
type Chunk struct {
ID string `json:"id"`
SessionID string `json:"session_id,omitempty"`
ProjectID string `json:"project_id,omitempty"`
ScopeKind string `json:"scope_kind"`
ScopeID string `json:"scope_id"`
SourceTurn string `json:"source_turn,omitempty"`
Content string `json:"content"`
ContentHash string `json:"content_hash"`
ToolName string `json:"tool_name,omitempty"`
FilesRead []string `json:"files_read,omitempty"`
FilesModified []string `json:"files_modified,omitempty"`
Title string `json:"title,omitempty"`
Embedding []float32 `json:"-"`
CreatedAt time.Time `json:"created_at"`
// Pinned chunks are immune to the prune sweep (FR-028).
Pinned bool `json:"pinned,omitempty"`
// RecallCount is the number of times this chunk has been retrieved
// by the kernel's MemoryNode / retriever. Updated lazily — the
// production store is the canonical recorder. Used by the
// recall-frequency prune signal.
RecallCount int `json:"recall_count,omitempty"`
// LastAccessed is the last time this chunk was read out of the
// store. Defaults to CreatedAt when zero. Used by the staleness
// prune signal.
LastAccessed time.Time `json:"last_accessed,omitempty"`
// Source records the originating hook boundary ("post-llm" etc.)
// so the inspector can show users why a chunk was captured.
Source string `json:"source,omitempty"`
// Kind classifies the chunk in the narrative layer
// (memory-narrative-layer-01KQ8TD1 WP01). One of: "raw",
// "narrative_extractive", "narrative_synthesised",
// "narrative_extractive_fallback". Empty values are backfilled to
// "raw" on load so legacy gobs are transparent.
Kind string `json:"kind,omitempty"`
// RetrievalWeight is the score multiplier applied during similarity
// search (WP01). Default 1.0 (no boost). Narrative chunks default
// to 1.5 (set by the narrative layer at write time). Zero values
// are backfilled to 1.0 on load.
RetrievalWeight float32 `json:"retrieval_weight,omitempty"`
// TurnID links this chunk to a specific agent turn for narrative
// keying. Used by the Promoter to correlate synthesised narratives
// with their extractive fallbacks. Empty for raw chunks.
TurnID string `json:"turn_id,omitempty"`
}
Chunk is one stored memory: an opt-in snippet the user explicitly asked the harness to keep across sessions.
Greedy-memory addendum (Bundle E WP15): the Pinned, RecallCount, and LastAccessed fields drive the background prune sweep. They default to the "fresh chunk" values when an old gob is read back (Pinned=false, RecallCount=0, LastAccessed=CreatedAt) so existing on-disk stores keep working without a migration.
Narrative-layer addendum (memory-narrative-layer-01KQ8TD1 WP01): Kind and RetrievalWeight were added without a gob schema migration. Existing on-disk stores read back with empty Kind and zero RetrievalWeight; backfillChunkDefaults in store.go sets them to "raw" and 1.0 so the retriever's score multiplier is transparent for legacy chunks.
type ChunkCounts ¶
type ChunkCounts struct {
// Total is the grand total number of chunks in the store.
Total int
// Raw is the count of chunks with ScopeKind "session".
// Named "raw" in the UI to match the spec's §2.4 display.
Raw int
// Narrative is the count of chunks with ScopeKind "narrative"
// (reserved for the future memory-narrative-layer; always 0 until
// that ship).
Narrative int
// LongTermPromoted is the count of chunks with ScopeKind "long_term"
// or "global". "global" is the current promotion target; long_term
// is reserved for a future scope tier.
LongTermPromoted int
// Embedded is the count of chunks that have a non-empty embedding
// vector (i.e. they can be retrieved by the k-NN search path).
Embedded int
// Unembedded is the count of chunks with an empty embedding vector.
// These are unretrievable until the user triggers re-embedding.
Unembedded int
}
ChunkCounts holds the per-kind breakdown of the total chunk count.
type Embedder ¶
type Embedder interface {
Kind() string
Dimensions() int
Embed(ctx context.Context, texts []string) ([][]float32, error)
}
Embedder turns text into vectors the Store can index. The interface is small on purpose — swapping providers (OpenAI, a local model, a mock for tests) is a one-implementation change.
type EmbedderEligibility ¶
type EmbedderEligibility struct {
// HasEligible is true when at least one profile in AllProfiles is
// eligible for use as an embedder.
HasEligible bool `json:"hasEligible"`
// AllProfiles is the total count of profiles that were examined.
AllProfiles int `json:"allProfiles"`
// EligibleProfiles is the count of profiles that are eligible.
EligibleProfiles int `json:"eligibleProfiles"`
// SkippedKinds holds the unique provider kinds that were present in
// the profile list but are not eligible (e.g. "anthropic", "bedrock").
// The frontend uses this list to render per-provider explanations in
// the "no memory provider" banner.
SkippedKinds []string `json:"skippedKinds"`
}
EmbedderEligibility reports which provider profiles are capable of supplying embeddings. It is designed to be called cheaply at settings load time so the frontend can surface a contextual banner when the user has only Anthropic-direct or Bedrock profiles.
func CheckEligibility ¶
func CheckEligibility(profiles []ProfileEligibilityInput) EmbedderEligibility
CheckEligibility walks profiles and returns an EmbedderEligibility summary. The logic mirrors newEmbedderFromProfiles's eligibleEmbedder inner function — but without constructing any network objects.
type EmbedderInfo ¶
type EmbedderInfo struct {
// Kind is the short provider tag ("openai", "noop", "fake", …).
Kind string
// Model is the embedding model identifier (e.g. "text-embedding-3-small").
// Empty for the noop embedder.
Model string
// Dimensions is the expected vector width. Zero for the noop embedder.
Dimensions int
}
EmbedderInfo surfaces the static properties of the currently-wired Embedder so the health panel can render "Provider / Model / Dimensions" without a network call.
type GateSetter ¶
type GateSetter interface {
SetGate(g MemoryWriteGate)
}
GateSetter is the optional capability tests + the rpc layer use to install a policy gate without re-opening the store. The chromem store implements it.
type HealthSnapshot ¶
type HealthSnapshot struct {
Counts ChunkCounts `json:"counts"`
Activity ActivityWindow `json:"activity"`
Embedder EmbedderInfo `json:"embedder"`
// CapturedAt is when the snapshot was taken (UTC).
CapturedAt time.Time `json:"capturedAt"`
}
HealthSnapshot is the wire-shape returned by HealthSnapshot(). All counts come from a single O(n) pass over the in-RAM store; there are no full-table scans or additional network calls.
func SnapshotHealth ¶
func SnapshotHealth(chunks []Chunk, embedder Embedder, now time.Time) HealthSnapshot
SnapshotHealth builds a HealthSnapshot over the given chunk slice. Called by chromemStore.SnapshotHealth after it acquires a read lock. Pure function — no I/O, safe for benchmarking.
type HealthSnapshotter ¶
type HealthSnapshotter interface {
SnapshotHealth(ctx context.Context) (HealthSnapshot, error)
}
HealthSnapshotter is the optional capability the Store must expose for the health-snapshot path. The chromemStore satisfies it via the SnapshotHealth helper below; test stubs and future backends can implement it directly.
The interface lives in core/memory (not core/rpc/views/memory) so the view layer never has to import core/memory internals beyond value types (DIRECTIVE_001 compliance).
type KeyResolver ¶
KeyResolver fetches the plaintext API key for a given OpenAI-kind provider. The rpc layer wires this against the credref resolver + secrets backend; tests pass a fake.
type MemoryWriteGate ¶
MemoryWriteGate is the narrow interface chromemStore consults on every Add. core/policy/cedar.Gate satisfies it via CheckMemoryWrite adapter; tests can pass a stub. The interface lives here to avoid pulling cedar into core/memory's import graph (DIRECTIVE_001).
type NoopEmbedder ¶
type NoopEmbedder struct{}
NoopEmbedder is the safe-by-default embedder used when no real one is wired. Embed always errors with ErrEmbedderUnavailable so the rpc layer can short-circuit "remember this" without persisting an unembedded chunk.
func (NoopEmbedder) Dimensions ¶
func (NoopEmbedder) Dimensions() int
func (NoopEmbedder) Kind ¶
func (NoopEmbedder) Kind() string
type OpenAIEmbedder ¶
type OpenAIEmbedder struct {
// contains filtered or unexported fields
}
OpenAIEmbedder is an Embedder backed by an OpenAI-compatible /v1/embeddings endpoint. Several provider Kinds reuse this type (openai, openrouter, custom_openai_compatible, azure) by overriding the endpoint via WithOpenAIEndpoint. Kind() reports the SOURCE provider Kind set via WithOpenAISourceKind so the health UI shows the actual upstream the user configured rather than the literal implementation type.
func NewOpenAIEmbedder ¶
func NewOpenAIEmbedder(resolveKey KeyResolver, opts ...OpenAIOption) *OpenAIEmbedder
NewOpenAIEmbedder constructs an OpenAI embedder. resolveKey is required; pass NoopEmbedder when no provider is configured.
func (*OpenAIEmbedder) Dimensions ¶
func (e *OpenAIEmbedder) Dimensions() int
func (*OpenAIEmbedder) Embed ¶
Embed posts texts to /v1/embeddings and returns one vector per input in the same order. Errors mirror the anthropic adapter's classify pattern: HTTP non-2xx becomes a wrapped error including the upstream body for support visibility.
func (*OpenAIEmbedder) Kind ¶
func (e *OpenAIEmbedder) Kind() string
Kind returns the SOURCE provider Kind (the upstream the user configured: "openai", "openrouter", "azure", "custom_openai_compatible"). Falls back to "openai" when no source was set, matching pre-v0.5.5 behaviour for callers that build embedders directly without going through newEmbedderFromProfiles.
type OpenAIOption ¶
type OpenAIOption func(*OpenAIEmbedder)
OpenAIOption configures an OpenAIEmbedder.
func WithOpenAIEndpoint ¶
func WithOpenAIEndpoint(u string) OpenAIOption
WithOpenAIEndpoint overrides the embeddings URL.
func WithOpenAIHTTPClient ¶
func WithOpenAIHTTPClient(c *http.Client) OpenAIOption
WithOpenAIHTTPClient overrides the http client (tests use httptest).
func WithOpenAIModel ¶
func WithOpenAIModel(m string) OpenAIOption
WithOpenAIModel overrides the embedding model id.
func WithOpenAISourceKind ¶
func WithOpenAISourceKind(k string) OpenAIOption
WithOpenAISourceKind sets the provider Kind that originated this embedder (e.g. "openrouter", "azure", "custom_openai_compatible"). Reported via Kind() so the health dashboard surfaces the actual upstream the user picked, not the literal "openai" implementation. Empty string falls back to "openai" for backwards compatibility with callers that don't set it.
type ProfileEligibilityInput ¶
type ProfileEligibilityInput struct {
Kind string
Endpoint string // only relevant for custom_openai_compatible and azure
// AzureComplete mirrors the Defaults map check in newEmbedderFromProfiles:
// true when deployment_id, api_version, and resource_name are all non-empty.
AzureComplete bool
}
ProfileEligibilityInput is the minimal profile fields CheckEligibility needs. Keeping this separate from core/llm.ProviderProfile avoids a circular import; the rpc layer maps ProviderProfile → ProfileEligibilityInput before calling CheckEligibility (see core/rpc/views/memory/impl.go).
type PruneCapable ¶
type PruneCapable interface {
SetPinned(ctx context.Context, id string, pinned bool) error
MarkAccessed(ctx context.Context, ids []string, at time.Time) error
}
PruneCapable is the optional capability the prune sweep uses to mark recall hits, pin/unpin chunks, and bulk-delete based on the pruner's verdict. Stores that don't implement it fall through to per-id Delete and the slower path the inspector RPC uses today.
SetPinned with pinned=true makes the chunk immune to the prune sweep (FR-028). MarkAccessed bumps RecallCount and updates LastAccessed atomically — the retriever should call it after every successful read so the prune sweep's recall-frequency signal reflects real usage.
type Result ¶
Result pairs a Chunk with its similarity score against a query embedding. Similarity is cosine; values close to 1 mean "highly related", values near 0 mean "unrelated".
type RetrievalHistory ¶
type RetrievalHistory struct {
// contains filtered or unexported fields
}
RetrievalHistory is the process-scoped ring buffer.
func GlobalRetrievalHistory ¶
func GlobalRetrievalHistory() *RetrievalHistory
GlobalRetrievalHistory returns the process-scoped singleton.
func (*RetrievalHistory) Last ¶
func (h *RetrievalHistory) Last(sessionID string) (RetrievalRecord, bool)
Last returns the most recent RetrievalRecord for the given session, and true when found. Returns zero-value, false when the session has no history.
func (*RetrievalHistory) Push ¶
func (h *RetrievalHistory) Push(rec RetrievalRecord)
Push records a retrieval call into the ring buffer. Enforces per-session and global caps, evicting oldest entries as needed.
func (*RetrievalHistory) Total ¶
func (h *RetrievalHistory) Total() int
Total returns the current total number of records across all sessions. Used in tests.
type RetrievalRecord ¶
type RetrievalRecord struct {
SessionID string
Query string
// Results holds ALL k-NN hits, sorted by similarity descending.
// The rpc layer partitions them into "injected" vs "below threshold"
// based on the retriever's configured threshold.
Results []RetrievalResult
Threshold float32
At time.Time
}
RetrievalRecord captures the outcome of one Retriever.retrieve call. It is the wire-agnostic internal shape; the rpc layer projects it into the frontend-visible RetrievalReport.
type RetrievalResult ¶
type RetrievalResult struct {
ChunkID string
Content string
Kind string
Pinned bool
Similarity float32
Injected bool // true when similarity >= threshold
}
RetrievalResult is one ranked chunk from a retrieval call.
type Retriever ¶
type Retriever struct {
// contains filtered or unexported fields
}
Retriever is the surface buildMessages calls to inject relevant snippets into the prompt. The concrete implementation lives here; callers use the Retrieve method only.
func NewRetriever ¶
func NewRetriever(store Store, embedder Embedder, enabledFn func() bool, threshold float32) *Retriever
NewRetriever constructs a Retriever. enabledFn is the settings-backed opt-in gate; nil means always disabled (safe default). threshold is the minimum cosine similarity a snippet must clear to be injected.
func (*Retriever) Retrieve ¶
Retrieve embeds query and returns up to k snippets above the configured similarity threshold. No scope filter is applied — every chunk is a candidate. The scoped variant (RetrieveScoped) is the WP06 contract; this thin wrapper is what older callers (and the rpc adapter that has not yet been updated to thread project id) hit.
func (*Retriever) RetrieveScoped ¶
func (r *Retriever) RetrieveScoped(ctx context.Context, query, sessionID, projectID string, k int) ([]Snippet, error)
RetrieveScoped runs a scope-union k-NN: global ∪ project:projectID ∪ session:sessionID. Empty sessionID or projectID drops the matching filter so callers can opt into whichever scopes apply (the persist path before WP02 lands has no project yet, for example).
func (*Retriever) WithSessionID ¶
WithSessionID returns a copy of the Retriever that records retrieval decisions into GlobalRetrievalHistory under the given session ID.
NARROWED 2026-08-20 (controls-and-readouts-that-tell-the-truth- 01PMZ808 WP11, FR-015): only the RetrieveScoped hook path calls this (core/rpc/api.go's retrieverAdapter.RetrieveScoped) — the sibling Retrieve path (retrieverAdapter.Retrieve) has no sessionID parameter to thread and does not call WithSessionID, so a retrieval driven through that path is not recorded into GlobalRetrievalHistory. The bare constructor still omits it for backwards compatibility / standalone (non-hooks) callers.
type ScopeFilter ¶
ScopeFilter targets chunks by (kind, id) for List / Query / Delete. An empty ID matches every chunk of the given kind (used for global, where ScopeID is always empty).
type ScopePromoter ¶
type ScopePromoter interface {
PromoteScope(ctx context.Context, oldID, newID, newScopeKind, newScopeID string) error
}
ScopePromoter is the optional capability the rpc/memory view uses to implement move semantics for "promote to project/global". The chromem-go-replacement store implements it; future backends should satisfy this interface so the view layer keeps the same contract.
type Snippet ¶
Snippet is the shape returned to callers — a content string + score. Mirrors llm.MemorySnippet so the rpc/views/llm package can consume it without importing core/memory directly.
type Store ¶
type Store interface {
Add(ctx context.Context, chunk Chunk) error
Delete(ctx context.Context, id string) error
List(ctx context.Context, scopes ...ScopeFilter) ([]Chunk, error)
Query(ctx context.Context, embedding []float32, k int, scopes ...ScopeFilter) ([]Result, error)
Close() error
}
Store is the long-term-memory persistence + retrieval contract.
func NewChromemStore ¶
NewChromemStore opens (or creates) the on-disk vector DB at path. A missing file is treated as an empty store; a corrupt file surfaces as an error so the user sees the problem instead of silently losing every memory.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package narrative implements the memory narrative layer (mission memory-narrative-layer-01KQ8TD1).
|
Package narrative implements the memory narrative layer (mission memory-narrative-layer-01KQ8TD1). |
|
Package prune is the background memory-prune subsystem (Bundle E WP15 of the agent-kernel-graph mission).
|
Package prune is the background memory-prune subsystem (Bundle E WP15 of the agent-kernel-graph mission). |