Memory Bridge and Context Injection
How OrchestKit injects past decisions into every prompt, captures new decisions automatically, and syncs memory across sessions through the knowledge graph.
The Memory Pipeline
OrchestKit maintains memory across sessions through a pipeline of hooks that capture, store, load, and inject context. The system follows a graph-first architecture: the knowledge graph (via MCP) is always available with zero configuration.
Session N Session N+1
--------- -----------
User prompt SessionStart
| |
v v
capture-user-intent ---> decisions.jsonl ---> memory-context-loader
| graph-queue.jsonl (once, first prompt)
v |
memory-context ---> search graph ---> additionalContext injected
(every prompt) for past decisions into Claude's context
|
v
Stop (fire-and-forget)
|
+--> graph-queue-sync (flush to graph)
+--> auto-remember-continuityMemory Context Loader (First Prompt)
Hook: prompt/memory-context-loader
Event: UserPromptSubmit (once: true)
Purpose: Load recent project decisions as context on the first prompt of every session.
This hook reads from .claude/memory/decisions.jsonl -- a file written by the capture-user-intent hook during previous sessions. Each line is a JSON record containing a decision or preference:
{
"id": "dec_abc123",
"type": "decision",
"content": {
"what": "Use cursor-based pagination for the orders API",
"why": "Offset pagination causes timeouts on tables with 1M+ rows"
},
"entities": ["cursor-pagination", "orders-api"],
"metadata": {
"timestamp": "2026-01-15T10:30:00Z",
"confidence": 0.85,
"category": "api",
"project": "myproject"
}
}The hook loads the last 10 decisions, formats them as markdown, and injects them via additionalContext:
## Recent Project Decisions
- **[Decision]** Use cursor-based pagination for the orders API _(because: Offset pagination causes timeouts on tables with 1M+ rows)_ [cursor-pagination, orders-api]
- **[Preference]** Use Tailwind CSS for all new components [frontend, tailwind]
- **[Decision]** PostgreSQL 16 for the analytics database _(because: Need JSONB and vector support)_ [PostgreSQL, analytics]
_For deeper graph traversal: use mcp__memory__search_nodes or mcp__memory__open_nodes_Budget Awareness
The context loader caps output at 3,000 characters to avoid consuming too much of the context window. If there are more decisions than fit within the budget, it truncates with a hint:
- _(additional decisions available via mcp__memory__search_nodes)_Memory Context (Every Prompt)
Hook: prompt/memory-context
Event: UserPromptSubmit (every prompt)
Purpose: Search the knowledge graph for context relevant to the current prompt.
Unlike the context loader (which runs once and injects recent decisions), this hook runs on every prompt and performs keyword-based relevance detection.
Trigger Detection
The hook checks the prompt against two keyword lists:
Memory triggers (suggest memory search would be valuable):
add, implement, create, build, design, refactor, update, modify, fix, change, continue, resume, remember, previous, last time, before, earlier, pattern, decision, how did we, what did we
Graph triggers (suggest relationship queries):
relationship, related, connected, depends, uses, recommends, what does.*recommend, how does.*work with
How It Works
Skip check. If the prompt is shorter than 20 characters, or contains no trigger keywords, the hook returns silently.
Extract search terms. Stopwords are removed and the prompt is reduced to 5 key terms.
Build context hint. The hook constructs a system message telling Claude how to search:
[Memory Context] For relevant past project decisions,
use mcp__memory__search_nodes with query="cursor pagination orders"Add relationship hints (if graph triggers detected):
For relationships: mcp__memory__open_nodes on found entities
| Graph traversal availableAdd agent context (if an agent is active):
Agent context: database-engineerThe hook does not execute the graph search itself -- it provides Claude with the instruction to do so. This keeps the hook fast (under 10ms) while giving Claude the information it needs to decide whether to query memory.
Global vs Project Scope
If the prompt starts with @global or mentions "cross-project" or "all projects", the hook switches to global scope:
[Memory Context] For relevant past cross-project decisions...Capture User Intent (Every Prompt)
Hook: prompt/capture-user-intent
Event: UserPromptSubmit (fire-and-forget via silent runner)
Purpose: Extract decisions and preferences from user prompts automatically.
This hook listens for decision signals in the user's natural language:
| Signal | Pattern | Example |
|---|---|---|
| Decision | "let's use X", "chose Y over Z", "going with X" | "Let's use PostgreSQL for the analytics DB" |
| Preference | "I prefer X", "always use X" | "I prefer Tailwind over styled-components" |
| Problem | "the issue is", "blocked by" | "The issue is that offset pagination times out" |
| Rationale | "because X", "since X" | "...because we need JSONB support" |
When a decision is detected, the hook:
- Creates a structured decision record with
what,why, entities, confidence score, and category - Appends it to
.claude/memory/decisions.jsonl(viastoreDecision) - Queues a graph memory write to
.claude/memory/graph-queue.jsonl
// The decision record structure
const record = createDecisionRecord({
what: "Use PostgreSQL for analytics",
why: "Need JSONB and vector support",
entities: ["PostgreSQL", "analytics"],
category: "database",
confidence: 0.85,
});
storeDecision(record, projectDir);The hook runs via the silent runner (run-hook-silent.mjs), meaning it produces no terminal output and does not block the prompt processing pipeline.
Queue-Based Memory Sync
Memory writes are not performed immediately during the session. Instead, they are queued to local JSONL files and flushed at session end via the fire-and-forget stop hooks.
Graph Queue
File: .claude/memory/graph-queue.jsonl
Flushed by: stop/graph-queue-sync
Each queued entry describes an entity or relation to create in the knowledge graph:
{
"action": "create_entity",
"entity": {
"name": "PostgreSQL",
"entityType": "Technology",
"observations": ["Selected for analytics database", "Chosen for JSONB and vector support"]
},
"timestamp": "2026-01-15T10:30:00Z"
}{
"action": "create_relation",
"relation": {
"from": "analytics-database",
"to": "PostgreSQL",
"relationType": "USES"
},
"timestamp": "2026-01-15T10:30:00Z"
}At session end, the graph-queue-sync hook reads the queue and executes the operations against the knowledge graph MCP.
Memory in Subagents
When a subagent is spawned, the graph memory inject hook provides memory context:
Graph Memory Inject
Hook: subagent-start/graph-memory-inject
Event: SubagentStart
Searches the knowledge graph for entities and relations relevant to the subagent's task, then injects them as additional context.
Memory Fabric Initializer
Hook: pretool/mcp/memory-fabric-init
Event: PreToolUse (mcp__memory__*) (once: true)
On the first MCP memory tool call of the session, this hook initializes the memory fabric -- setting up the connection to the knowledge graph. It runs once and silently.
Memory Validator
Hook: pretool/mcp/memory-validator
Event: PreToolUse (mcp__memory__*)
Validates knowledge graph operations before they execute, ensuring entity names are properly formatted and relation types follow the expected vocabulary.
The Three-Tier Memory Architecture
OrchestKit's hooks bridge three storage tiers:
| Tier | Storage | Written By | Read By |
|---|---|---|---|
| 1. Knowledge Graph | MCP mcp__memory__* | graph-queue-sync (stop) | memory-context (prompt), graph-memory-inject (subagent) |
| 2. Local JSONL | .claude/memory/*.jsonl | capture-user-intent (prompt), memory-writer | memory-context-loader (first prompt) |
| 3. CC Native | MEMORY.md | High-confidence decisions (>= 0.7) auto-written | Claude Code system prompt (automatic) |
All three tiers require zero configuration and always work. CC Native memory (Tier 3) is written automatically for high-confidence decisions and persists even without OrchestKit installed.
Auto-Remember Continuity
Hook: stop/auto-remember-continuity (fire-and-forget)
At session end, this hook reviews the session's key decisions and ensures they are stored for the next session. It acts as a safety net -- if capture-user-intent missed a decision during the session, this hook catches it during the cleanup pass.
Profile Injector
Hook: prompt/profile-injector
Event: UserPromptSubmit (once: true)
On the first prompt, this hook injects the user's profile context (project identity, team conventions, preferred tools) from .claude/context/identity.json. This is separate from memory -- it provides static configuration rather than learned decisions.
Summary: Which Hooks Touch Memory?
| Hook | Event | Direction | Frequency |
|---|---|---|---|
memory-context-loader | UserPromptSubmit | Read (JSONL) | Once per session |
memory-context | UserPromptSubmit | Read hint (graph) | Every prompt |
capture-user-intent | UserPromptSubmit | Write (JSONL + queues) | Every prompt |
graph-memory-inject | SubagentStart | Read (graph) | Per subagent |
memory-fabric-init | PreToolUse (MCP) | Setup | Once per session |
memory-validator | PreToolUse (MCP) | Validate | Per MCP call |
graph-queue-sync | Stop | Write (graph) | Once at exit |
auto-remember-continuity | Stop | Write (all) | Once at exit |
profile-injector | UserPromptSubmit | Read (config) | Once per session |
Security Gates and File Guards
How OrchestKit blocks dangerous commands, protects sensitive files, and auto-approves safe operations -- the defense-in-depth hooks that run before every tool use.
Create Your Own Hook
Step-by-step guide to writing, registering, building, and testing a custom OrchestKit hook -- from TypeScript types to esbuild bundles.
Last updated on