Solves the problem of Claude forgetting design decisions and constraints across conversations by storing structured project memory as JSON files in your repo. You get ten tools to record decisions with required rationale fields (problem, why_chosen, tradeoffs), pipeline workflows with ordering, and constraints with enforcement levels. The get_context tool pulls related entries via ID links, and hooks inject summaries at session start plus snapshot context before Claude Code compaction to catch anything lost. Enforces minimum character counts on reasoning fields so agents can't write lazy one-liners. All data lives in .context/ as human-editable files. Useful when working on projects that span multiple conversations where Claude needs to remember why you chose approach X over Y.
Project memory for Claude. Records design decisions, pipeline flows, and constraints so Claude maintains context across conversations.
As conversations get long, Claude loses the "why" behind earlier decisions. New conversations start blank. This causes Claude to make changes that break established patterns — like rewriting a pipeline step it doesn't remember exists.
Context Keeper gives Claude 10 tools to record and retrieve structured project context:
| Tool | Purpose |
|---|---|
record_decision | Save a decision with structured rationale (problem, why_chosen, what_we_tried, tradeoffs) |
record_pipeline | Save a multi-step workflow with ordering and purpose |
record_constraint | Save a rule with scope, enforcement level, and triggering_incident |
get_context | Retrieve relevant entries by query, tags, scope, or ID — pulls related_to links by default |
get_project_summary | Compact overview for conversation start |
update_entry | Update any entry by ID |
deprecate_entry | Retire an entry with reason |
prune_stale | Find entries not verified recently |
get_compaction_report | Check if last compaction lost any context |
verify_quality | Scan entries for thin rationale, missing tags, isolated arcs (auto-called by PreCompact hook) |
All data stored as human-editable JSON files in .context/ inside your project directory. Zero external dependencies.
Earlier versions used a single freeform rationale field. In practice, agents wrote one-line summaries instead of full reasoning — defeating the point. v0.4 fixes this three ways:
record_decision requires problem (min 40 chars), why_chosen (min 60 chars), and accepts optional what_we_tried and tradeoffs. record_pipeline requires purpose. record_constraint enforces reason ≥ 40 chars and accepts optional triggering_incident. Thin entries are rejected server-side with field-specific guidance — the lazy path no longer produces a useful entry.related_to. Every entry can reference IDs of related entries. get_context traverses these links by default (depth=1), so when you retrieve one decision the rest of its arc comes along. Connective tissue survives across sessions.verify_quality tool scans for legacy entries, thin reasoning, missing tags, and isolated entries (tag overlap with no related_to). The PreCompact hook calls it automatically and surfaces flagged entries so they can be enriched before context is compressed.Legacy entries (pre-v0.4) stay valid — they're never auto-rejected, just flagged by verify_quality for optional enrichment. The deprecated rationale parameter still works on record_decision for backward compatibility (it auto-maps to why_chosen), but problem is still required.
pip install context-keeper-mcp
claude mcp add --scope user context-keeper -- python /path/to/context-keeper/server.py
Add to your claude_desktop_config.json:
{
"mcpServers": {
"context-keeper": {
"command": "python",
"args": ["/path/to/context-keeper/server.py"],
"env": {
"CONTEXT_KEEPER_PROJECT": "/path/to/your/project"
}
}
}
}
Set CONTEXT_KEEPER_PROJECT to the root of your project. If omitted, the server resolves the project directory in this order:
CONTEXT_KEEPER_PROJECT env var (explicit opt-in — trusted).context/ directory.context/ (git-style discovery — finds your project when the server is launched from any subdirectory of it)record_* returns an "unresolved project" errorSteps 2 and 3 only resolve to directories that already contain .context/. The server never creates one implicitly, so you can never accidentally pollute a parent directory by launching from the wrong place. Pass project_dir explicitly to any tool to force-create a new project.
When you make a design decision:
You: Let's use JSON files instead of SQLite for storage.
Claude: [calls record_decision with summary, problem, why_chosen, alternatives,
and optionally what_we_tried + tradeoffs + related_to links]
When you establish a workflow:
You: The deploy pipeline is: run tests, build, push to registry, deploy.
Claude: [calls record_pipeline with ordered steps]
When you set a rule:
You: Never run Conductor from source. Always use the exe.
Claude: [calls record_constraint with rule, reason, and hardness=absolute]
At conversation start, the SessionStart hook injects the project summary (and any compaction-discrepancy report) directly into context — no tool call required, so retrieval can't be skipped on a task-focused first turn. get_project_summary remains callable on demand. Before making changes, Claude calls get_context with relevant tags to check for conflicts.
Without embeddings or external services, Context Keeper scores entries using:
Results are capped by a configurable token budget (default: 4000 tokens).
Context Keeper includes hooks that inject project memory at session start, remind Claude to capture after every git commit, snapshot your context before Claude Code compaction, and detect if anything was lost afterward.
Add to your Claude Code hooks config (~/.claude/settings.json):
{
"hooks": {
"PreCompact": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "python /path/to/context-keeper/hooks/pre_compact.py"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "python /path/to/context-keeper/hooks/post_compact.py"
}
]
}
],
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "python /path/to/context-keeper/hooks/session_start.py"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python /path/to/context-keeper/hooks/commit_capture_reminder.py"
}
]
}
]
}
}
Replace /path/to/context-keeper with the actual install path. Set CONTEXT_KEEPER_PROJECT env var if your project isn't in the current working directory.
Windows users: Use forward slashes (C:/Users/.../context-keeper/hooks/pre_compact.py) or double-escaped backslashes in JSON. Single backslashes get mangled by the shell.
The hooks form a complete capture-and-retrieval loop:
.context/ yet, and emits ASCII-only output so it cannot crash on Windows cp1252 stdoutgit commit, it injects a reminder to record the matching decision/constraint/gotcha in the same work cycle. A commit is the single best capture trigger — it's the exact moment something became real enough to persist in version control. Born from field use: during incident-heavy sessions the agent batched capture "for later," and the user had to ask "update context keeper" three times in one night while a dozen commits shipped.context/ entries, runs a quality scan (verify_quality), and prints a capture prompt + any flagged entries (thin reasoning, missing tags, isolated arcs) so Claude can enrich them before context is compressedThis closes the capture loop: SessionStart injects retrieval at turn one, the commit reminder anchors capture to the moment changes land, PreCompact is the pre-compression safety net, and Stop handles integrity checking. Retrieval is unavoidable; capture is now prompted at the right moment rather than left to the agent's discretion mid-task.
your-project/
.context/
decisions.json # Design decisions with rationale
pipelines.json # Multi-step workflows
constraints.json # Rules and invariants
config.json # Token budget, stale threshold
compaction_snapshot.json # Pre-compaction snapshot (auto-generated)
compaction_report.json # Post-compaction diff report (auto-generated)
hook.log # Hook activity log
All files are human-readable JSON. You can edit them directly. IDs are sequential and readable: dec-001, pipe-001, con-001.
Create .context/config.json to customize:
{
"project_name": "my-project",
"token_budget": 4000,
"max_entry_tokens": 1000,
"stale_threshold_days": 30
}
Query another project's context by passing project_dir:
Claude: [calls get_context with project_dir="/path/to/other-project"]
Or tag entries with other project names for cross-referencing.
CONTEXT_KEEPER_PROJECTAbsolute path to the project directory. Defaults to current working directory.
io.github.ericm1018/skillfm-llm-cost-optimizer-openai-anthropic-usage
io.github.mikerawsonnz/llm-orchestration-agent
io.github.mikerawsonnz/authenticated-llm-agent
labforgedev/copilot-memory-mcp
csoai-org/agent-prompt-injection-firewall-mcp
io.github.mikerawsonnz/authenticated-multi-llm-agent