Documentation
¶
Overview ¶
Package memory implements jcode's cross-session learned memory: a file-based store under ~/.jcode/memory with a per-project root, an online note inbox (L1), a summary/index read path injected into the system prompt, and usage accounting that feeds the offline distillation pipeline (L2). See internal-doc/agent-memory-design.md.
Index ¶
- Constants
- func BuildInjection(projectDir string, cfg *config.Config) string
- func ClearScope(scopeRoot string) (busy bool, err error)
- func EnsureScope(scopeRoot string) error
- func GlobalRoot() string
- func NewPathGuardMiddleware(root string) adk.ChatModelAgentMiddleware
- func NewUsageMiddleware() adk.ChatModelAgentMiddleware
- func ProjectRoot(projectDir string) string
- func ProjectSlug(projectDir string) string
- func RecordUsage(absPath string)
- func Redact(s string) string
- func Root() string
- func ScopeRootFor(scope, projectDir string) string
- func TruncateRunes(s string, maxChars int, suffix string) string
- func TryLockPipeline(scopeRoot string) (func(), bool, error)
- func UpdateState(scopeRoot string, fn func(*State) error) error
- func WithoutUsageAccounting(ctx context.Context) context.Context
- func WriteNote(n Note) (string, error)
- type ConsolidationRecord
- type ExtractRecord
- type FileUsage
- type Note
- type NoteFile
- type State
Constants ¶
const ( SummaryFile = "memory_summary.md" IndexFile = "MEMORY.md" NotesDir = "notes" SummariesDir = "session_summaries" StateFile = "state.json" )
Layout, relative to a scope root (global/ or projects/<slug>/):
memory_summary.md consolidated summary, injected into the system prompt MEMORY.md grep-able index (maintained by the consolidation agent) notes/ L1 inbox: one small fact per file, <ts>-<slug>.md session_summaries/ phase-1 products (M2) skills/ distilled reusable workflows (M3, SKILL.md format) state.json usage accounting / pipeline coordination
const MaxNoteBytes = 64 * 1024
MaxNoteBytes caps a single note (memory tool official guidance: bound file sizes at the implementation layer).
Variables ¶
This section is empty.
Functions ¶
func BuildInjection ¶
BuildInjection renders the memory section appended to the system prompt. Returns "" when there is nothing worth injecting (zero cost for fresh projects). The content is injected transiently per model call — it never enters the session history, so it cannot be compacted away or pollute summaries (same principle as eino's agentsmd middleware).
func ClearScope ¶
ClearScope removes a scope's memory directory, coordinating with the pipeline lock so a running distillation cannot resurrect a half-cleared scope.
It reports busy=true (deleting nothing) if the pipeline currently holds the lock — the caller should ask the user to retry. Otherwise it holds the lock across the delete (a concurrent pipeline's non-blocking TryLockPipeline keeps failing), which closes the release-then-delete race the naive version had. On Windows RemoveAll can hit a sharing violation on the still-open lock file; once the handle is released a retry succeeds, so we release then retry.
func EnsureScope ¶
EnsureScope creates the standard layout for a scope root.
func GlobalRoot ¶
func GlobalRoot() string
GlobalRoot returns the scope root for cross-project memory.
func NewPathGuardMiddleware ¶
func NewPathGuardMiddleware(root string) adk.ChatModelAgentMiddleware
NewPathGuardMiddleware confines every tool call to root: any path-bearing argument that resolves outside root is rejected before the tool runs. This is the implementation-level containment for the consolidation subagent — it does not rely on the prompt.
func NewUsageMiddleware ¶
func NewUsageMiddleware() adk.ChatModelAgentMiddleware
NewUsageMiddleware returns the middleware; safe to add unconditionally (it is a no-op for tool calls that never touch the memory root).
func ProjectRoot ¶
ProjectRoot returns the scope root for a project working directory.
func ProjectSlug ¶
ProjectSlug derives the stable per-project directory name: <sanitized-basename>-<hash8-of-canonical-path>. The hash keeps same-named projects apart; the basename keeps the directory human-readable.
func RecordUsage ¶
func RecordUsage(absPath string)
RecordUsage bumps the usage counter for a memory file. absPath must be an absolute path somewhere under Root(); anything else is silently ignored so the middleware can call this unconditionally.
func Redact ¶
Redact masks common credential shapes before anything is persisted to the memory store. It runs on memory_note input, phase-1 pipeline input and output (see design §6.1). Idempotent: redacted text passes through unchanged.
func Root ¶
func Root() string
Root returns the memory root directory (~/.jcode/memory). It follows config.ConfigDir() so isolated-HOME test environments are respected.
func ScopeRootFor ¶
ScopeRootFor maps a memory_note scope value to its directory.
func TruncateRunes ¶
TruncateRunes truncates s to at most maxChars bytes without splitting a UTF-8 rune, then appends suffix. Byte-count budgeting (not rune count) is intentional — token/size limits are byte-based — but the cut lands on a rune boundary so multibyte text (e.g. Chinese) is never corrupted.
func TryLockPipeline ¶
TryLockPipeline takes the scope's non-blocking pipeline lock. Returns a release func and whether the lock was acquired (false = another process is already running the pipeline).
func UpdateState ¶
UpdateState applies fn to the scope's state under an exclusive file lock and persists the result atomically. Lost updates are prevented by re-reading inside the lock.
func WithoutUsageAccounting ¶
WithoutUsageAccounting marks a context so the usage middleware ignores tool calls made under it. The consolidation agent reads every memory file each run; letting that count as "usage" would distort the ranking signal.
Types ¶
type ConsolidationRecord ¶
type ConsolidationRecord struct {
At string `json:"at"` // RFC3339
NoopFastPath bool `json:"noop_fast_path"`
Decisions map[string]int `json:"decisions,omitempty"` // op → count
Commit string `json:"commit,omitempty"`
}
ConsolidationRecord summarizes a phase-2 run (M3). Decisions holds the ADD/UPDATE/DELETE/NOOP protocol output so runs are assertable.
type ExtractRecord ¶
type ExtractRecord struct {
At string `json:"at"` // RFC3339
SummaryFile string `json:"summary_file,omitempty"`
UsageCount int `json:"usage_count"`
LastUsage string `json:"last_usage,omitempty"`
Failed bool `json:"failed,omitempty"`
FailCount int `json:"fail_count,omitempty"` // consecutive extraction failures (backoff)
Error string `json:"error,omitempty"`
}
ExtractRecord tracks one extracted session (phase 1, M2).
type FileUsage ¶
type FileUsage struct {
UsageCount int `json:"usage_count"`
LastUsage string `json:"last_usage,omitempty"` // RFC3339
}
FileUsage is the usage-feedback loop: bumped whenever the agent reads a memory file (see UsageMiddleware), consumed by consolidation ranking.
type Note ¶
type Note struct {
Scope string // "project" (default) | "global"
Kind string // preference | fact | pitfall | workflow
Source string // "user" (explicit "remember X") | "agent"
Text string
SessionID string
Cwd string
}
Note is one L1 inbox entry. Notes only ever land in the notes/ inbox — the curated files (MEMORY.md, memory_summary.md) are maintained solely by the phase-2 consolidation agent, keeping cheap-and-fast decoupled from expensive-and-curated.
type NoteFile ¶
NoteFile is a parsed inbox note (for injection and /memory display).
func RecentNotes ¶
RecentNotes returns up to limit inbox notes for a scope, newest first.
type State ¶
type State struct {
Version int `json:"version"`
// Files tracks read-usage per memory file (scope-root-relative path).
// Consolidation ranks by usage and expires long-unused entries.
Files map[string]*FileUsage `json:"files,omitempty"`
// Extracted tracks phase-1 work per source session UUID (M2).
Extracted map[string]*ExtractRecord `json:"extracted,omitempty"`
// Budget is the pipeline token ledger per day ("2026-07-04" → tokens).
Budget map[string]int64 `json:"budget,omitempty"`
// LastConsolidation records the most recent phase-2 outcome (M3).
LastConsolidation *ConsolidationRecord `json:"last_consolidation,omitempty"`
// LastPipelineAt is when the pipeline last ran (cooldown gate). RFC3339.
LastPipelineAt string `json:"last_pipeline_at,omitempty"`
}
State is the per-scope coordination file (state.json). It replaces the SQLite database Codex uses: entry counts are in the thousands at most, and flock + atomic rename matches the concurrency conventions of internal/session and internal/automation.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package pipeline implements the offline memory distillation pipeline (design §5): phase 1 extracts durable facts per ended session with a cheap model; phase 2 consolidates them into curated artifacts with a restricted subagent, git-diff driven with a zero-token no-op fast path.
|
Package pipeline implements the offline memory distillation pipeline (design §5): phase 1 extracts durable facts per ended session with a cheap model; phase 2 consolidates them into curated artifacts with a restricted subagent, git-diff driven with a zero-token no-op fast path. |