Gini memory is visible, governable, and local by default.
Gini has three memory surfaces (see ADR runtime-identity-files.md for the partition):
- USER.md — instance-scoped user identity, always injected into the prompt. Edited via the
edit_user_profiletool, auto-approved when the injection scan passes (a flagged body routes through.proposedfor review). - SOUL.md — per-agent persona, always injected. Edited via the
edit_soultool, auto-approved when the injection scan passes (a flagged body routes through.proposedfor review). - Hindsight — per-agent SQLite bank populated automatically by auto-retain at the end of every chat task. Queried by recall on each turn and by the
recall_memorytool on demand.
This document covers Hindsight; USER.md / SOUL.md are documented in runtime-identity-files.md.
Hindsight units live in ~/.gini/instances/<instance>/memory.db using SQLite. The model cache for local embeddings and reranking lives in ~/.gini/models/.
Hindsight is scoped per agent. Each agent owns its own bank, units carry the active agent id, and recall filters on it across every channel. Switching the active agent changes which memories are recalled. New agents start with an empty bank; configuration is copied at creation, content is not. See ADR agent-memory-isolation.md for the isolation contract.
flowchart LR
User[User / agent event] --> Retain[Retain]
Retain --> Unit[Memory unit]
Unit --> SQLite[(memory.db)]
SQLite --> Recall[Recall]
Recall --> Context[Context for future work]
Context --> Agent[Agent response or action]
SQLite --> Reflect[Reflect]
Reflect --> Summary[Reflected summary]
Summary --> SQLite
Memory is not hidden prompt stuffing. Hindsight records memory units with provenance and retrieves them through multiple signals on demand.
- Retain: write a memory unit with source/provenance metadata. The auto-retain pipeline runs at the end of every chat task and populates the bank without any tool call.
- Recall: retrieve relevant memory with semantic, lexical, graph, and temporal signals. Surfaced via the
recall_memorytool and the per-turn automatic recall. - Reflect: propose higher-level memory from existing evidence.
- Reinforce: update strength and relationships as memories are used.
flowchart TD
Input[Task, chat, job, or manual memory] --> Extract[Extract candidate facts]
Extract --> Classify[Classify network/type]
Classify --> Entities[Resolve entities and links]
Entities --> Embed[Embed text if semantic provider is enabled]
Embed --> Store[(SQLite memory.db)]
Store --> Audit[Audit event]
Store --> Trace[Trace evidence when tied to execution]
Retain keeps enough metadata to answer: where did this memory come from, what entities does it touch, what model embedded it, and what runtime action created it.
Recall fuses four channels:
- semantic vector search
- BM25/lexical search
- graph spreading activation
- temporal recency and cadence
Results are combined with reciprocal rank fusion, reranked over the top candidates, and packed into a token budget.
flowchart TD
Query[Current user request] --> Semantic[Semantic vector search]
Query --> Lexical[BM25 / lexical search]
Query --> Graph[Entity graph activation]
Query --> Temporal[Temporal matching]
Semantic --> RRF[Reciprocal rank fusion]
Lexical --> RRF
Graph --> RRF
Temporal --> RRF
RRF --> Rerank[Cross-encoder reranker]
Rerank --> Pack[Token-budget pack]
Pack --> Context[Memory context sent to agent]
The four channels cover different failure modes:
- semantic catches meaning even when words differ
- lexical catches exact names, commands, and phrases
- graph catches related entities and relationships
- temporal catches time-sensitive facts and recent context
Hindsight units do not flow through a propose/approve gate — auto-retain writes them directly to the bank. Provenance metadata (source task, source trace ids, embedding model) is recorded with every unit so the user can review them on the Memory page and prune individual units as needed. Curated identity edits to USER.md and SOUL.md auto-apply when clean and route through the propose/approve gate only when the injection scan flags them, see ADR runtime-identity-files.md.
Providers:
localby default: Transformers.js withXenova/all-MiniLM-L6-v2openai:text-embedding-3-smallecho: deterministic test provider
Useful commands:
bun run gini embedding status
bun run gini embedding reembedEnvironment overrides:
GINI_EMBEDDING_PROVIDER=local|openai|echo
GINI_LOCAL_EMBEDDING_MODEL=<hf-id>Different embedding models use different vector spaces. Switching providers does not destroy existing memories, but semantic recall only uses memory units embedded by the active model until they are re-embedded.
Providers:
localby default: Transformers.js withXenova/ms-marco-MiniLM-L-6-v2echo: deterministic test providernone: skip cross-encoder reranking
Useful commands:
bun run gini reranker statusEnvironment overrides:
GINI_RERANKER_PROVIDER=local|echo|none
GINI_LOCAL_RERANKER_MODEL=<hf-id>
GINI_RERANKER_TOP_N=<int>Smoke tests pin echo providers so parallel smoke runs and CI do not download models.
gini memory {retain|recall|reflect|units|banks|migrate}— CLI subcommands./api/memory/retain,/api/memory/recall,/api/memory/reflect,/api/memory/units,/api/memory/banks— API contracts.- The
recall_memoryagent tool (defaultmemorytoolset). - The web Memory page.
Memory should become more useful without becoming hidden magic. Future work should improve contradiction handling, compaction, bank governance, provenance, and review workflows.