# https://github.com/jarmstrong158/context-keeper Project Manual

Generated at: 2026-07-26 00:24:34 UTC

## Table of Contents

- [Overview & System Architecture](#page-1)
- [Core Tools, Data Model & Retrieval](#page-2)
- [Hooks & Capture-Time Guardrails](#page-3)
- [Two-Way Mirror & Remote Sync (v0.15)](#page-4)

<a id='page-1'></a>

## Overview & System Architecture

### Related Pages

Related topics: [Core Tools, Data Model & Retrieval](#page-2)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/jarmstrong158/context-keeper/blob/main/README.md)
- [pyproject.toml](https://github.com/jarmstrong158/context-keeper/blob/main/pyproject.toml)
- [server.py](https://github.com/jarmstrong158/context-keeper/blob/main/server.py)
- [CLAUDE.md](https://github.com/jarmstrong158/context-keeper/blob/main/CLAUDE.md)
- [context_keeper/__init__.py](https://github.com/jarmstrong158/context-keeper/blob/main/context_keeper/__init__.py)
- [context_keeper/store.py](https://github.com/jarmstrong158/context-keeper/blob/main/context_keeper/store.py)
- [context_keeper/retrieval.py](https://github.com/jarmstrong158/context-keeper/blob/main/context_keeper/retrieval.py)
- [hooks/scope_guard.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/scope_guard.py)
</details>

# Overview & System Architecture

## Purpose and Scope

context-keeper is an MCP (Model Context Protocol) memory server that gives coding agents durable, queryable knowledge about a project's decisions, constraints, conventions, and prior session outcomes. It runs as a local stdio server, ships as the PyPI package `context-keeper-mcp`, and is designed to be installed once per project so every connected agent shares the same store. Its distinguishing architectural commitments are stated explicitly in the project documentation: zero runtime dependencies, offline-by-default operation, and human-readable on-disk storage. Source: [README.md:1-40]()

The server exposes a small set of `record_*` and query tools (notably `record_decision`, `update_entry`, `deprecate_entry`, plus retrieval endpoints) plus a `hooks/` directory of MCP hook handlers that react to client events such as `SessionStart` and `PostToolUse`. Decisions written through these tools are indexed for both lexical and semantic recall, projected to an optional `DECISIONS.md` for human readers, and reinjected at session start via `additionalContext` so the next agent inherits the prior team's reasoning. Source: [CLAUDE.md:1-60]()

## High-Level Architecture

The system has three logical layers, all running in a single Python process and communicating with the MCP client over stdio:

| Layer | Responsibility | Representative modules |
|-------|----------------|------------------------|
| MCP transport / tool surface | JSON-RPC framing, `tools/list`, tool dispatch, `additionalContext` delivery | `server.py`, `context_keeper/__init__.py` |
| Domain logic | Entry CRUD, supersession, ranking, abstention, summary generation, markdown projection | `context_keeper/store.py`, `context_keeper/retrieval.py` |
| Persistence and hooks | Atomic file writes, index files, hook-driven constraint injection | `context_keeper/store.py`, `hooks/scope_guard.py` |

The project ships with an audited build (v0.15.0) that tightened stdio UTF-8 handling, fixed a mirror-watermark data-loss bug, and trimmed the PyPI description for registry validation. Source: [pyproject.toml:1-40]()

```mermaid
flowchart LR
    Agent[MCP client / agent] -->|tools/call| Server[server.py]
    Agent -->|SessionStart / PostToolUse| Hooks[hooks/scope_guard.py]
    Server --> Store[(context_keeper/store.py)]
    Hooks -->|additionalContext| Agent
    Store -->|write via os.replace| Disk[(Entry JSON files)]
    Store --> Index[(Lexical + semantic index)]
    Store -->|render-on-write| MD[DECISIONS.md]
    Index --> Server
```

## Core Subsystems

### Entry store and data integrity

Entries are persisted as individual files keyed by id, with writes performed through a temp-file + `os.replace` swap so a mid-write crash cannot corrupt existing entries. If a target entry file exists but cannot be parsed, mutating tools (`record_*`, `update_entry`, `deprecate_entry`) refuse to write rather than silently overwriting, preserving recoverability. This guard was introduced alongside the broader v0.5.0 data-integrity pass. Source: [context_keeper/store.py:1-120]()

### Retrieval: lexical, semantic, and abstention

Recall combines lexical scoring with pluggable embedding backends (multiple backends landed in v0.9.0) and optional clustering. Two ranking ideas were adapted from the competitor Curion: **supersession-as-ranking** (newer decisions outrank the entries they replace) and **abstention** (return a clear "no relevant memory" signal when nothing crosses a confidence threshold, rather than fabricating context). The project's release notes explicitly note that Curion's per-call LLM controller was rejected to keep the server zero-dependency and offline. Source: [context_keeper/retrieval.py:1-160]()

### Capture-time guardrails and hooks

The `hooks/` package implements MCP hooks. `hooks/scope_guard.py` runs as a `PostToolUse` hook on `Edit|Write|NotebookEdit`: when an agent edits a file that falls under a stored constraint's `scope`, the matching constraint is injected via `additionalContext`. This complements the session-start injection of project rules, enforcing them at the exact moment they are most likely to be violated. Source: [hooks/scope_guard.py:1-80]()

### Session-start summary and tool-schema budget

At `SessionStart` the server calls `get_project_summary`, which renders the canonical store into a token-bounded briefing. A regression test caps the `tools/list` payload at roughly 2,500 estimated tokens after v0.7.1 trimmed per-tool descriptions (for example, `record_decision`'s description dropped from ~738 to a much smaller figure), so future schema additions must fit the budget. Source: [server.py:1-160]()

### Markdown projection and retrieval hints

When `markdown_export.enabled` is set, every decision mutation re-renders `DECISIONS.md` synchronously (render-on-write), giving humans a version-controllable view of the same data the agent sees. Separately, every `record_*` tool accepts `retrieval_hints` — two to four anticipated future phrasings — which are indexed alongside the entry body to mitigate vocabulary-mismatch queries. Source: [context_keeper/store.py:120-220]()

## Design Principles

Three principles recur across the changelog and the contributor guidance in `CLAUDE.md`:

1. **Zero-dependency, offline-first.** All ranking, embedding (where a local backend is configured), and persistence happen in-process; no network calls are required for core operation. Source: [pyproject.toml:1-40]()
2. **Source of truth is the file store.** Hooks and tools derive state from the same on-disk entries, and the optional `DECISIONS.md` is a projection rather than a separate source. Source: [CLAUDE.md:1-60]()
3. **Bounded context budgets.** Both the `tools/list` schema and the `SessionStart` summary are explicitly token-capped with regression tests, so growth in capability cannot silently erode the agent's working context. Source: [server.py:1-160]()

Together these choices make context-keeper a small, auditable memory layer that an agent team can adopt per repository without surrendering locality, determinism, or human readability.

---

<a id='page-2'></a>

## Core Tools, Data Model & Retrieval

### Related Pages

Related topics: [Overview & System Architecture](#page-1), [Hooks & Capture-Time Guardrails](#page-3), [Two-Way Mirror & Remote Sync (v0.15)](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [server.py](https://github.com/jarmstrong158/context-keeper/blob/main/server.py)
- [semantic_index.py](https://github.com/jarmstrong158/context-keeper/blob/main/semantic_index.py)
- [usage.py](https://github.com/jarmstrong158/context-keeper/blob/main/usage.py)
- [code_drift.py](https://github.com/jarmstrong158/context-keeper/blob/main/code_drift.py)
- [work_focus.py](https://github.com/jarmstrong158/context-keeper/blob/main/work_focus.py)
- [mirror.py](https://github.com/jarmstrong158/context-keeper/blob/main/mirror.py)
- [hooks/scope_guard.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/scope_guard.py)
</details>

# Core Tools, Data Model & Retrieval

The MCP surface of context-keeper is intentionally narrow: a small set of `record_*` mutation tools, a single `update_entry` / `deprecate_entry` pair for lifecycle, a session-start `get_project_summary` reader, and a retrieval layer that fuses lexical and semantic matching. Everything is zero-dependency, offline by default, and persisted as one JSON file per entry under the project store.

## Core Tools

The tools defined in `server.py` form the public API that every connected MCP client loads into context. Their schemas are tightly trimmed (see v0.7.1) so that the cumulative `tools/list` payload stays under the ~2500-token regression cap.

| Tool | Purpose | Key fields |
|------|---------|------------|
| `record_decision` | Capture a new decision | `text`, `rationale`, `tags`, `scope`, `origin`, `retrieval_hints` |
| `update_entry` | Edit an existing entry in place | `entry_id`, patched fields |
| `deprecate_entry` | Soft-delete / supersede | `entry_id`, `supersedes`, `reason` |
| `get_project_summary` | Session-start injection | truncation-bounded summary |

`record_decision` alone previously consumed ~738 estimated tokens in its schema description; the v0.7.1 budget pass cut the whole surface from ~2800 to ~2370 tokens, and added a regression test that fails any future field which would breach 2500. Source: [server.py:1-1]()

Mutation tools reject writes when an entry file already exists but cannot be parsed, and they always perform an atomic temp-file + `os.replace` swap. A crash mid-write therefore cannot leave a half-written entry on disk. Source: [server.py:1-1]()

## Data Model

Entries are flat JSON documents persisted one-per-file in the project store. Every mutation tool (`record_*`, `update_entry`, `deprecate_entry`) re-derives indexes and exports in the same call, so the store stays self-consistent without a background process. Source: [server.py:1-1]()

The canonical shape includes:

- `id` — stable identifier used by `update_entry` / `deprecate_entry`
- `text`, `rationale` — captured content
- `tags` — short labels for grouping
- `scope` — file patterns a constraint applies to (consumed by `hooks/scope_guard.py` via PostToolUse on `Edit|Write|NotebookEdit`)
- `origin` — provenance trust tag (introduced in v0.7.0)
- `retrieval_hints` — 2–4 alternate phrasings indexed for both lexical and semantic search
- `supersedes` — list of superseded entry ids; supersession is treated as a ranking signal, not a deletion

The `mirror.py` module projects the canonical store into auxiliary surfaces. When `markdown_export.enabled` is true, every decision mutation re-renders the human-readable `DECISIONS.md` at the configured path (render-on-write, no separate watcher). Source: [mirror.py:1-1]()

`usage.py` records per-tool invocation telemetry that feeds the work-focus signals, while `code_drift.py` cross-references stored entries against the current working tree so stale decisions can be surfaced.

## Retrieval

Retrieval is the part of the system where context-keeper diverges most visibly from LLM-controller competitors like Curion. There is no per-query API call: matching runs entirely on local indexes built from the entry text plus its `retrieval_hints`. Source: [semantic_index.py:1-1]()

The pipeline combines:

1. **Lexical matching** over the text and `retrieval_hints` fields (the zero-dependency fix for vocabulary-mismatch queries introduced in v0.7.0).
2. **Semantic matching** through `semantic_index.py`, which supports multiple embedding backends added in v0.9.0.
3. **Clustering** — entries with similar embeddings are grouped so that recalling one surfaces related context without needing every entry to match the exact phrasing.
4. **Abstention** — when the combined score falls below a threshold the system returns no result rather than a low-confidence match (introduced in v0.10.0, adapted from studying Curion's design while keeping context-keeper offline).
5. **Supersession-as-ranking** — a deprecated entry that has been superseded is demoted in result order rather than hidden, preserving auditability of the decision lineage.

`get_project_summary` is the session-start projection of this same store. It was the subject of a critical v0.9.0 fix: the truncation loop previously evaluated the *original* text in its `while` condition, so any store whose summary exceeded the token budget silently emitted an empty summary. The fix evaluates the *truncated* text, and the regression test now pins behavior for stores above the budget threshold. Source: [server.py:1-1]()

## Work Focus and Drift

`work_focus.py` consumes the usage telemetry from `usage.py` to compute what the agent has been actively editing, and feeds that into retrieval boost so recently-touched entries rank higher in the next session. Source: [work_focus.py:1-1]()

`code_drift.py` runs a periodic comparison between entry `scope` / referenced symbols and the current file tree, flagging decisions whose referenced files no longer exist or whose content has moved substantially. Drift signals are surfaced through the same retrieval surface, not as a separate tool, so the agent encounters them in the natural flow of recall rather than as a noisy background task. Source: [code_drift.py:1-1]()

---

<a id='page-3'></a>

## Hooks & Capture-Time Guardrails

### Related Pages

Related topics: [Core Tools, Data Model & Retrieval](#page-2), [Two-Way Mirror & Remote Sync (v0.15)](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- Source: [hooks/session_start.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/session_start.py)
- Source: [hooks/pre_compact.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/pre_compact.py)
- Source: [hooks/post_compact.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/post_compact.py)
- Source: [hooks/scope_guard.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/scope_guard.py)
- Source: [hooks/constraint_reinject.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/constraint_reinject.py)
- Source: [hooks/commit_capture_reminder.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/commit_capture_reminder.py)
</details>

summary>

The following source files were used to generate this page:

- [hooks/session_start.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/session_start.py)
- [hooks/pre_compact.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/pre_compact.py)
- [hooks/post_compact.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/post_compact.py)
- [hooks/scope_guard.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/scope_guard.py)
- [hooks/constraint_reinject.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/constraint_reinject.py)
- [hooks/commit_capture_reminder.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/commit_capture_reminder.py)
- [hooks/__init__.py](https://github.com/jarmstrong158/context-keeper/blob/main/hooks/__init__.py)
</details>

# Hooks & Capture-Time Guardrails

context-keeper is a zero-dependency MCP memory server that relies on a set of small, single-purpose **hooks** to inject context at the moments when it matters most. The hooks collectively form *capture-time guardrails* — automatic reminders and constraint re-injections that fire the moment an agent begins a session, edits a file, runs a pre-compaction summarization, or prepares a commit. Each hook is independent, JSON-config-driven, and safe to fail silently so that MCP client behavior is never blocked. Source: [hooks/__init__.py]()

## Hook Inventory and Lifecycle Placement

Six hooks ship in the `hooks/` package, each tied to a different stage of the agent loop:

| Hook | Trigger | Primary Purpose |
|------|---------|-----------------|
| `session_start.py` | SessionStart / first turn | Load `get_project_summary` and active constraints into context |
| `pre_compact.py` | PreCompact | Snapshot relevant memory before the host summarizes the conversation |
| `post_compact.py` | PostCompact | Re-inject project summary and constraints after compaction |
| `scope_guard.py` | PostToolUse on `Edit|Write|NotebookEdit` | Inject constraint text when a touched file falls inside a constraint's `scope` |
| `constraint_reinject.py` | Recurring / turn boundary | Re-brief constraints that are still active in the current session |
| `commit_capture_reminder.py` | Pre-commit / git hook | Remind the agent (or human) to capture any pending decisions before commit |

This placement is deliberately redundant: critical context is re-broadcast at every transition where a model could otherwise lose it. Source: [hooks/session_start.py](), [hooks/post_compact.py](), [hooks/scope_guard.py]()

## Session-Start and Summary Injection

`hooks/session_start.py` runs once when a client connects. It calls into the MCP server's `get_project_summary` tool to assemble a token-bounded project briefing — typically the most recent decisions, constraints, and superseded entries — and returns it through Claude Code's `additionalContext` channel. Since v0.5.0, the truncation loop walks the rendered text instead of the raw entries, which fixes the empty-injection bug that previously occurred for stores with ~30+ entries. Source: [hooks/session_start.py](), referencing the v0.9.0 release notes fix.

The pre-compact and post-compact hooks form a complementary pair. `pre_compact.py` records the current snapshot of relevant memory so a later recall can recover context that the host's auto-compactor is about to throw away. `post_compact.py` then re-injects the summary and constraints, mirroring the session-start behavior so the agent resumes with an intact brief. Source: [hooks/pre_compact.py](), [hooks/post_compact.py]()

## Scoped Constraint Injection (v0.6.0)

`hooks/scope_guard.py` is the headline feature of the v0.6.0 *Capture-time guardrails* release. Constraints stored in the decisions store can declare a `scope` — a glob, path prefix, or language tag that identifies the files they apply to. The hook subscribes to **PostToolUse** on `Edit`, `Write`, and `NotebookEdit` so it can inspect the file the agent is about to (or has just) modified. When the touched path matches a constraint's `scope`, the hook immediately injects the constraint's prose into context via `additionalContext`. Source: [hooks/scope_guard.py]()

The design rationale, as documented in the v0.6.0 release, is that **session-start injection briefs the rules once at turn one, but `scope_guard` enforces them at the exact moment the agent is most likely to violate them**. A constraint that says "never edit `migrations/` without a backup" is harmless if it has already scrolled out of the model window; firing it on the PostToolUse event restores it just-in-time. The hook is read-only against the memory store and returns a non-blocking dictionary, so a misconfigured scope never aborts the underlying tool call. Source: [hooks/scope_guard.py]()

## Recurring Re-injection and Capture Reminders

Two hooks address drift across longer sessions. `constraint_reinject.py` periodically re-asserts constraints that are still active but may have been pushed out of the model's context window. Unlike `scope_guard`, it does not depend on a file event — it is triggered by the host's recurring hook callback (or by a turn-boundary check) and re-emits the constraint text verbatim. This supplements, rather than replaces, `scope_guard`, because not every constraint is scoped to a file. Source: [hooks/constraint_reinject.py]()

`commit_capture_reminder.py` is the final guardrail. It fires before any git commit and prompts the agent to record any latent decisions it has not yet stored — a common blind spot, since commits frequently codify behavior that was decided mid-session but never persisted as a `record_decision` call. The hook reads the staged diff, compares file paths and symbols against the in-memory store, and emits a reminder listing entries that look like they should be captured. Source: [hooks/commit_capture_reminder.py]()

## Design Properties

Across all six hooks, three properties are consistent:

1. **Zero-dependency**: every hook imports only from the MCP server's own `__main__` and the standard library, preserving the project's offline-first posture. Source: [hooks/__init__.py]()
2. **Fail-soft**: hook handlers catch and log exceptions internally, returning an empty `additionalContext` rather than raising — so a broken constraint file or unreadable store cannot crash the host. Source: [hooks/scope_guard.py](), [hooks/constraint_reinject.py]()
3. **Render-on-read, not render-on-write**: hooks re-query the live store on every invocation rather than caching, which keeps tooling token costs predictable and avoids stale-context bugs. Source: [hooks/session_start.py](), [hooks/post_compact.py]()

Together these hooks turn context-keeper from a passive memory store into an active guardrail layer, ensuring that decisions, constraints, and project summaries are surfaced at precisely the moments the agent is most likely to need — or forget — them.

---

<a id='page-4'></a>

## Two-Way Mirror & Remote Sync (v0.15)

### Related Pages

Related topics: [Core Tools, Data Model & Retrieval](#page-2)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [mirror.py](https://github.com/jarmstrong158/context-keeper/blob/main/mirror.py)
- [server.py](https://github.com/jarmstrong158/context-keeper/blob/main/server.py)
- [server.json](https://github.com/jarmstrong158/context-keeper/blob/main/server.json)
- [glama.json](https://github.com/jarmstrong158/context-keeper/blob/main/glama.json)
- [mcpb/manifest.json](https://github.com/jarmstrong158/context-keeper/blob/main/mcpb/manifest.json)
- [scripts/build-mcpb.sh](https://github.com/jarmstrong158/context-keeper/blob/main/scripts/build-mcpb.sh)
</details>

# Two-Way Mirror & Remote Sync (v0.15)

## Purpose and Scope

The Two-Way Mirror is a synchronization subsystem that keeps a derived, human-readable projection of the canonical decision store in lockstep with the on-disk entries managed by `server.py`. Rather than introducing a separate LLM-controlled controller layer, context-keeper’s mirror stays pure-Python, zero-dependency, and offline-by-default. The mirror module lives in [mirror.py](https://github.com/jarmstrong158/context-keeper/blob/main/mirror.py) and is invoked at every decision-mutation boundary so that the projected artifact cannot drift from the canonical store. Source: [mirror.py:1-1]()

The "two-way" terminology reflects the bidirectional responsibility of the module:

- **Canonical → projected:** on every `record_decision`, `update_entry`, or `deprecate_entry` mutation, the canonical entry is re-rendered into the mirror artifact.
- **External → canonical:** the same module exposes the read path that reconciles the mirror’s watermark with the on-disk entry set during sync.

This subsystem first shipped as opt-in `markdown_export` configuration in v0.8.0 and was hardened for production in the v0.15.0 audited build. Source: [mirror.py:1-1]()

## Rendering Pipeline

The mirror is a render-on-write projection. Every mutation observed by `server.py` forwards to `mirror.py` to regenerate the projected file. The configuration is minimal and stored alongside other context-keeper settings:

```json
{
  "markdown_export": {
    "enabled": true,
    "path": "DECISIONS.md"
  }
}
```

Key behavioral properties:

- **Idempotent regeneration** — the entire projected file is rewritten on each call, so partial corruption is impossible to observe in the output.
- **Path-controlled** — the `path` field determines where the artifact is written; defaults to `DECISIONS.md` at the project root.
- **Mutation-triggered** — write events come exclusively from the record/update/deprecate tools; read-side traffic does not trigger regeneration. Source: [mirror.py:1-1]()

## v0.15 Audit Fixes

The v0.15.0 release repaired three defects specific to the mirror subsystem, all of which had been latent since the v0.8.0 introduction:

| Defect | Symptom | Fix |
|--------|---------|-----|
| Mirror watermark data-loss | The watermark tracking which canonical entries had been projected could be reset, causing previously projected decisions to disappear from the mirror output across restarts. | Watermark persistence path corrected so that progress is durable across process restarts. |
| `mirror.py` packaging | The module was not always shipped inside the bundled distribution, causing imports of mirror helpers to fail under `python -m context_keeper` invocations. | Packaging manifest updated to include `mirror.py`; verified by [scripts/build-mcpb.sh](https://github.com/jarmstrong158/context-keeper/blob/main/scripts/build-mcpb.sh). |
| UTF-8 stdio | The stdio transport could mangle non-ASCII entries during mirror-triggered writes. | Encoding explicitly set to UTF-8 on all stdio paths. |

Source: [v0.15.0 release notes](https://github.com/jarmstrong158/context-keeper/releases/tag/v0.15.0), [mirror.py:1-1]()

## Packaging and Distribution

The mirror module ships with the MCP server bundle. The audited v0.15.0 build ensures that whenever a user installs context-keeper via any of the supported packaging channels, `mirror.py` is present and importable:

- **PyPI (`context-keeper-mcp`)** — the wheel includes `mirror.py` after the packaging fix; verified by the build script before publish.
- **MCP registry (`server.json`)** — the entrypoint references the corrected module set; the registry manifest in [server.json](https://github.com/jarmstrong158/context-keeper/blob/main/server.json) is consistent with the wheel contents.
- **Anthropic / Glama registries** — the auxiliary manifests in [glama.json](https://github.com/jarmstrong158/context-keeper/blob/main/glama.json) and the MCPB bundle declared in [mcpb/manifest.json](https://github.com/jarmstrong158/context-keeper/blob/main/mcpb/manifest.json) list the same entrypoint, ensuring no channel ships a partial install.
- **MCPB bundle** — produced by [scripts/build-mcpb.sh](https://github.com/jarmstrong158/context-keeper/blob/main/scripts/build-mcpb.sh), which archives the project tree after explicitly verifying that `mirror.py` is included.

Source: [server.json:1-1](), [glama.json:1-1](), [mcpb/manifest.json:1-1](), [scripts/build-mcpb.sh:1-1]()

## When to Enable the Mirror

The mirror is opt-in. Recommended usage patterns from project history:

- Enable it in repositories where humans regularly read decisions without an MCP client available (the `DECISIONS.md` artifact is a Markdown file and works in any text viewer or version-control diff tool).
- Disable it in automated CI environments where each record-tool call would trigger a write to the working tree and conflict with concurrent jobs.
- Keep it disabled when the canonical store is the only authoritative surface and no external consumer needs a Markdown view.

Source: [mirror.py:1-1](), [v0.8.0 release notes](https://github.com/jarmstrong158/context-keeper/releases/tag/v0.8.0)

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Pitfall Log

Project: jarmstrong158/context-keeper

Summary: Found 7 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Configuration risk - Configuration risk requires verification.

## 1. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.host_targets | https://github.com/jarmstrong158/context-keeper

## 2. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.assumptions | https://github.com/jarmstrong158/context-keeper

## 3. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/jarmstrong158/context-keeper

## 4. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: downstream_validation.risk_items | https://github.com/jarmstrong158/context-keeper

## 5. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: risks.scoring_risks | https://github.com/jarmstrong158/context-keeper

## 6. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/jarmstrong158/context-keeper

## 7. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/jarmstrong158/context-keeper

<!-- canonical_name: jarmstrong158/context-keeper; human_manual_source: deepwiki_human_wiki -->
