Skip to main content

MCP server that captures and retrieves architectural decisions and context for Claude Code sessions

Project description

Contexer

Contexer is a lightweight MCP server for Claude Code that automatically captures decisions made during coding sessions and surfaces them at the start of every future session — so Claude never starts blind.

The problem

Every Claude Code session starts with no memory of the previous one. CLAUDE.md files require manual maintenance and go stale. When Claude works autonomously, the reasoning behind decisions disappears when the session ends. Teams end up re-explaining the same constraints, conventions, and architecture choices every time.

Contexer solves this by capturing decisions as they happen — silently, automatically, in the background — and replaying them as project rules at session start.


Quick start

Install takes under two minutes. See docs/install.md for full steps, verification, and uninstall. For hooks, tool internals, filter logic, and storage layout see docs/architecture.md.

Plugin (recommended):

/plugin marketplace add bhargavamin/contexer
/plugin install contexer@contexer
/reload-plugins

Manual:

git clone git@github.com:bhargavamin/contexer.git ~/tools/contexer
bash ~/tools/contexer/scripts/install.sh

After install, open a new Claude Code session in any repo. If no context exists, Claude will automatically run a bootstrap to capture your first decisions. If context exists, all constraints and conventions are injected at session start.


How it works

You work normally. Contexer runs in the background via Claude Code hooks.

Session opens
  └─▶ All conventions + constraints injected as project rules
      Architecture/pattern decisions available on demand (JIT)
      First session with no context → bootstrap runs automatically

You type a prompt
  └─▶ Your first message is stored as the current task description
  └─▶ "Why/reason/rationale/decided" questions auto-fetch matching decisions

Claude works
  └─▶ Calls get_context when it needs architecture or pattern context
  └─▶ Calls update_context when it makes a significant decision

Context window nears limit
  └─▶ Claude is reminded to save any unsaved decisions before compaction
  └─▶ After compaction, full context is reloaded automatically

You never call any tool directly. Claude handles all tool calls. If Claude misses something, say "store that decision" and it will call update_context immediately.


Decision types

Every stored decision has a subtype that controls when and how it is surfaced.

Subtype What it captures Injected at session start?
constraint Rules that must always apply — "never commit untested code" Yes — always
convention Team or project standards — "use uv not pip", "conventional commits" Yes — always
architecture Structural decisions — "chose FastMCP over low-level mcp.Server" No — fetched on demand
pattern Recurring implementation approaches — "plain dicts as function boundaries" No — fetched on demand

Constraints and conventions are injected directly at every session start because they apply to every task. Architecture and pattern decisions are large and task-specific — Claude fetches them just-in-time when the task requires them.


Managing decisions

All operations use natural language. Claude translates them into the right tool call.

Store a decision

"store that as a constraint"
"save this as a convention: always use uv not pip"
"remember this architecture decision"

Claude calls update_context with the content and the appropriate subtype. The server applies a novelty filter before storing — content with more than 70% token overlap with an existing decision is silently discarded as a duplicate.

Note: Your first prompt each session is automatically stored as the task description — not as a decision or constraint. If you open a session with an instruction like "always update docs before committing", it is captured as the task, not stored as a constraint. To store it as a constraint, either complete the turn (Claude will call update_context at the end) or explicitly say "store that as a constraint".

Query decisions

"show me all constraints"
"what decisions did we make about postgres?"
"show everything stored for this repo"
Example call What it returns
get_context() Latest 10 decisions — overview
get_context(entry_type="constraint") Up to 25 constraints
get_context(query="postgres") Up to 25 decisions matching "postgres"
get_context(limit=50) Up to 50 decisions

Update a decision

"update the uv decision — we switched back to pip"
"correct the constraint about commit format"

Claude calls update_context with the revised content. The old entry is not removed — a new entry is added alongside it. If the revised content is too similar to the original (>70% token overlap), it will be filtered as a duplicate. Rephrase it to include what changed.

Remove a decision

"delete the postgres decision"
"remove all outdated constraints"

Claude reads ~/.contexer/<repo_slug>.json and removes the matching entry directly. The file is plain JSON — you can also edit or prune it manually at any time.


Tools reference

Tool Triggered by What it does
capture_context UserPromptSubmit hook — once per session Stores the first prompt as the task description
update_context Claude, mid-task Nominates a decision; server filters before storing
get_context Claude, on demand Returns stored decisions — filtered by keyword or subtype
get_context_for_prompt UserPromptSubmit hook — every prompt Detects rationale questions and auto-injects matching decisions
bootstrap_context Claude, first session with no context Scans repo stack for inferable decisions; surfaces gap questions

Storage

Decisions are stored locally at ~/.contexer/<repo_slug>.json — one file per repo, capped at 500 entries. No cloud, no database, no accounts.

Each entry contains:

Field Values
id UUID
type task or decision
subtype architecture | constraint | pattern | convention
content The full decision text
session_id UUID for the session that created it
timestamp ISO 8601 UTC

Inspect the store at any time:

cat ~/.contexer/<repo_slug>.json

Troubleshooting

Claude isn't storing decisions automatically. Claude calls update_context at the end of significant decisions, not continuously. If something specific was missed, say "store that decision" and Claude will call it immediately.

A decision was stored but later ignored. Constraints and conventions are injected at session start. If you added a new constraint mid-session, it will appear from the next session onward.

A decision is outdated or wrong. Say "delete the X decision" or edit ~/.contexer/<repo_slug>.json directly and remove the entry.

The novelty filter rejected a new decision. If the content is too similar to an existing one (>70% token overlap), it is silently discarded. Rephrase it to be more specific, or remove the old entry first.

No context was injected at session start. If no decisions are stored for the repo, the bootstrap flow runs instead. Complete bootstrap once and all future sessions will have context.


License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

contexer-0.1.0.tar.gz (70.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

contexer-0.1.0-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

File details

Details for the file contexer-0.1.0.tar.gz.

File metadata

  • Download URL: contexer-0.1.0.tar.gz
  • Upload date:
  • Size: 70.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for contexer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a4a4c76b7b79d9d744d6314c5a2e8398a0322fcef342fa0080faf6af5500d687
MD5 932a99bd06abd0bc0f23254972f9ae37
BLAKE2b-256 0a58c1efa9bc578bab62b60364e4b58ad2eb83d4490e275206eab18d253232a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for contexer-0.1.0.tar.gz:

Publisher: publish.yml on bhargavamin/contexer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file contexer-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: contexer-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for contexer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6b604331d66f95178550758320f30817433f06db4c6bdf361df4421656afa8c8
MD5 7fb4f8730f2f2724a402de3acb8191aa
BLAKE2b-256 da4ecfa7cafdb397f3cf27924a5220ebcb1be4a60824b9d67052edc9e70faaf4

See more details on using hashes here.

Provenance

The following attestation bundles were made for contexer-0.1.0-py3-none-any.whl:

Publisher: publish.yml on bhargavamin/contexer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page