memory¶
memory adds durable, provenance-bound recall for information that should
outlive one task: prior decisions, constraints, procedures, preferences, facts,
and bounded episodes.
It is deliberately separate from:
context-handoff, which owns authoritative current task state;indexkit, which owns semantic/hybrid search across document corpora;- repository and runtime evidence, which determine what is true now.
Memory results are leads. The workflow always recalls, opens the original source, checks freshness, and verifies consequential claims before acting.
Install¶
memory depends on context-handoff, which pulls verify and then
retrieval-core.
Memory model¶
Every context-kit/memory-v1 record has three retrieval layers:
- immutable evidence or a precise evidence pointer;
- one concise primary memory;
- zero to three cue anchors for alternate phrasing.
Project records also carry repository, branch, HEAD, observation/capture times, source hash, review state, freshness, and supersession links. New abstractions never replace the evidence from which they were derived.
This independently implemented design combines MemPalace's useful verbatim storage/rebuildable-index boundary with Memora-inspired primary memories, cue anchors, rank fusion, evidence links, and reviewable consolidation.
Local-only capture¶
The adapter uses Python 3.10+ plus Git on PATH and can preserve reviewed records
without an external provider:
export CONTEXT_KIT_MEMORY_PROJECT=owner/repository
export CONTEXT_KIT_MEMORY_ROOT="/path/to/context-kit/plugins/memory"
python3 "$CONTEXT_KIT_MEMORY_ROOT/scripts/memory-provider.py" \
validate record.md
python3 "$CONTEXT_KIT_MEMORY_ROOT/scripts/memory-provider.py" \
capture record.md --provider none
Records default to ~/.local/share/context-kit/memory; override
CONTEXT_KIT_MEMORY_HOME.
Semantic recall with the first-party rag provider¶
Local recall is lexical. The bundled rag provider adds offline semantic
recall using indexkit, which memory hard-depends on, so no external
memory provider is needed. Embeddings still come from a locally running
Ollama. Claude Code and GitHub Copilot CLI bootstrap the indexkit venv on
session start; elsewhere, either install the published CLI or bootstrap the
venv with uv:
pip install indexkit # or: bash plugins/indexkit/scripts/bootstrap.sh
ollama pull nomic-embed-text
export CONTEXT_KIT_MEMORY_PROVIDER=rag
export CONTEXT_KIT_MEMORY_PROJECT=owner/repository
python3 "$CONTEXT_KIT_MEMORY_ROOT/scripts/memory-provider.py" doctor
python3 "$CONTEXT_KIT_MEMORY_ROOT/scripts/memory-provider.py" sync-provider --apply
python3 "$CONTEXT_KIT_MEMORY_ROOT/scripts/memory-provider.py" \
search "why did we change retry policy" --results 8
doctor resolves the indexkit executable and reports ready for either
runtime. When no usable indexkit is found it refuses with the exact bootstrap
command; doctor --bootstrap builds the plugin venv, which needs uv. That
matters most on APM, which does not deploy hooks, and after an upgrade leaves a
stale venv.
The index is a rebuildable projection of accepted/current records, never the
system of record: hits are bound back to the local records, so review,
freshness, source, and source_hash come from the immutable artifacts. When
the provider is unreachable, search falls back to lexical local search and
labels it degraded_from; a stale index refuses instead of degrading.
Optional MemPalace provider¶
MemPalace is installed separately:
uv tool install mempalace
export CONTEXT_KIT_MEMORY_PROVIDER=mempalace
export CONTEXT_KIT_MEMORY_PROJECT=owner/repository
export CONTEXT_KIT_MEMORY_HOME="$HOME/.local/share/context-kit/memory"
python3 "$CONTEXT_KIT_MEMORY_ROOT/scripts/memory-provider.py" doctor
python3 "$CONTEXT_KIT_MEMORY_ROOT/scripts/memory-provider.py" \
search "why did we change retry policy" --results 8
The adapter gives each project an isolated palace below
CONTEXT_KIT_MEMORY_HOME, invokes exact argv without a shell, and preserves a
local exact copy before provider archival. It does not vendor MemPalace, install
dependencies, enable a writable MCP server, or use a global knowledge graph.
Explicit workflows¶
| Command | Purpose |
|---|---|
/capture-memory |
Create and validate one proposed/accepted durable record. |
/recall-memory |
Search project memory, then open and verify the source. |
/review-memory |
Check freshness/conflicts and propose supersession. |
/archive-handoff |
Preserve one validated handoff as historical evidence. |
Consolidation is propose-only. A replacement creates a new record and
supersedes edge; prior evidence remains auditable.
The continuity integration test archives a current handoff, captures an accepted local record from that preserved source, recalls its labels, and then proves newer repository state takes precedence. No MemPalace process or network is involved.
Mine past Copilot sessions¶
propose-from-session extracts the human-visible conversation from GitHub
Copilot CLI logs (~/.copilot/session-state/<id>/events.jsonl) into reviewable
context-kit/memory-candidate-v1 candidates:
python3 "$CONTEXT_KIT_MEMORY_ROOT/scripts/memory-provider.py" \
propose-from-session ~/.copilot/session-state # dry run
python3 "$CONTEXT_KIT_MEMORY_ROOT/scripts/memory-provider.py" \
propose-from-session ~/.copilot/session-state --write
Attribution is the hard part. Copilot logs all activity in one stream, and a
subagent task prompt is written by the orchestrating model, not the person.
Across a real 115-session corpus, 611 of 729 user.message events carried
parentAgentTaskId and 94 carried a generated source, leaving 24 genuine
human turns. Extraction keeps a user turn only when it has neither; assistant
turns require neither parentToolCallId nor parentAgentTaskId. Reasoning
fields are never extracted.
Mining proposes and never captures — a transcript is not an atomic memory, so
authoring a record from a candidate is an explicit judgment step. Dry run is the
default, credential findings block the write unless --redact is passed, and
repository/branch/HEAD anchors are required rather than invented.
MCP surface¶
An optional stdio MCP server lets hosts that consume skills plus MCP — including GitHub Copilot and Claude Code plugin installs — use durable memory:
Three tools are exposed — memory_recall, memory_capture, and
memory_review — because a connected server advertises its schemas into context
on every turn. The bundled MCP definition forwards explicit project/home
configuration into the server. GitHub Copilot Desktop can instead use a trusted
ephemeral binding: SessionStart requires payload sessionId to exactly match
COPILOT_AGENT_SESSION_ID, then resolves payload cwd to the Git top-level and
accepts only a canonical github.com/owner/repository origin on POSIX. MCP cwd,
PWD, prompt content, and tool arguments cannot select another project store.
Windows, other Git hosts, and deeper namespaces require explicit scope. MCP
capture requires an absolute evidence path because plugin hosts may launch
outside the active repository. Memory clears the "reach for MCP last" bar
because it is live local state plus actions, not static knowledge a skill could
carry.
The server is a surface, not a source of truth: every tool shells out to
memory-provider.py with exact argv, so validation, isolation, and review state
have one implementation. The surface can propose memory but cannot activate
it — a record that is not review: proposed is refused, and proposals stay
out of active recall until promoted with the append-only record-state CLI.
sync-provider, promotion, mining, and destructive operations are not exposed.
Lifecycle hooks and opt-in capture¶
Recall injection and payload queuing ship disabled. Enable capture only after provider setup, project scoping, and a retention/privacy decision:
export CONTEXT_KIT_MEMORY_PROVIDER=mempalace
export CONTEXT_KIT_MEMORY_PROJECT=owner/repository
export CONTEXT_KIT_MEMORY_AUTO_CAPTURE=true
Enabled Stop, PreCompact, and SessionEnd hooks save exact mode-0600 payloads
for explicit review. They never create memory-v1 records or write a provider.
APM does not deploy plugin hooks, so its default remains explicit capture unless the user separately configures a native MemPalace integration.
Copilot's project binding is the bounded routing-only exception to the disabled
hook behavior. It stores only session_id and normalized project under
CONTEXT_KIT_MEMORY_HOME/session-bindings/ (mode-0700 directory, atomic
mode-0600 files), never a transcript or memory record. Repeated starts are
idempotent, a same-session cross-project mismatch is refused, and a matching
SessionEnd removes the binding. Stop/agentStop does not. Crash leftovers
are isolated by unique host session IDs.
Configuration¶
| Variable | Purpose |
|---|---|
CONTEXT_KIT_MEMORY_PROVIDER |
none (default), rag, or mempalace. |
CONTEXT_KIT_MEMORY_HOME |
Reviewed records and project-isolated provider data. |
CONTEXT_KIT_MEMORY_PROJECT |
Explicit project scope; overrides a trusted Copilot session binding and is required on unsupported hosts. |
CONTEXT_KIT_MEMORY_AUTO_CAPTURE |
Enables Claude lifecycle forwarding when truthy. |
CONTEXT_KIT_MEMORY_ROOT |
Installed plugin root for portable command use. |
CONTEXT_KIT_MEMPALACE_BIN |
Optional absolute MemPalace executable override. |
CONTEXT_KIT_INDEXKIT_BIN |
Optional absolute rag executable override. |
Safety defaults¶
- no automatic capture unless explicitly enabled;
- no global project-memory fallback;
- no project inference from MCP cwd,
PWD, prompts, or tool arguments; - no destructive consolidation;
- no transcript harvesting by the context-kit adapter — session mining proposes reviewable candidates and never creates memory records;
- no claim of current truth without source/freshness checks;
- no duplicate repository corpus indexing by default.