Skip to main content
Glama
zachvp
by zachvp
README.md
# Context Bridge
This file is the practical "how do I actually run this" companion.
See `PLAN.md` for the original design rationale and vague roadmap. 

## Installation
```bash
bash scripts/wizard.sh
```

The wizard creates a `.venv`, installs dependencies, registers the MCP server
with Claude Code (global by default, so it's available in every session), and
writes a `.env` file for local config.

**Configuration** — `.env` (created by the wizard, gitignored) supports:

| Variable | Default | Purpose |
|---|---|---|
| `CONTEXT_BRIDGE_DB_PATH` | `./chat_memory.db` | Where the database lives |
| `CONTEXT_BRIDGE_MODEL` | `BAAI/bge-base-en-v1.5` | fastembed model ID; changing after a build triggers a full rebuild |
| `CONTEXT_BRIDGE_BATCH_SIZE` | `64` | Embedding batch size; reduce to `16` or `8` if you hit OOM during build |

Edit `.env` directly to change these after initial setup. See `.env.example` for
the template.

**Changing the embedding model:** set `CONTEXT_BRIDGE_MODEL` to a different
fastembed-compatible model ID, then run a **full rebuild** with your
complete Claude.ai export — `build_db.py` detects the model mismatch and skips
the partial-export merge to avoid mixing incompatible vectors. Partial exports
are safe again after the first full rebuild with the new model.

## Getting your Claude.ai export

There is no API for this — the export is pull-only, triggered manually:

1. Go to **Claude.ai → Settings → Account → Export Data**
2. Anthropic emails you a `.dms` file attachment (has been a few minutes in my exp)
3. Run `./scripts/build_all.sh path/to/export.dms` (or `.zip`) — it handles the rename, unpack, and rebuild

## Abstract overview

```
Claude.ai export (.zip)                ~/.claude/projects/**/*.jsonl
      │  unzip                                │  ingest_code_sessions.py
      ▼                                       │  (incremental, walk parentUuid tree)
data/inspect/                                 │
      │  ingest.py + embed.py                 │
      │  (full rebuild via build_db.py)       │
      └──────────────────┬────────────────────┘
                         ▼
               chat_memory.db   (SQLite — chunks + sessions + meta)
                         │  source: 'claude_ai' | 'claude_code'
                         │  server.py: search_chat_history, get_conversation
                         ▼
               Claude Code session, via "context-bridge" MCP
```

`build_db.py` always parses the entire `data/inspect/` export and re-embeds
everything, but before the atomic replace it merges back any `claude_ai`
chunks from the previous DB whose conversation/project UUID is absent from the
new export. This means a partial export (e.g. 90-day-only) is safe — older
history that isn't in the new export is preserved from the old DB.

**One exception:** if the embedding model changes between builds, the merge is
skipped (mixing vectors from two models would corrupt search). In that case run
`build_db.py` with a full export to get a clean rebuild.

## Commands

Each shell script accepts `--help` for full usage and options. Quick reference:

| Script | Purpose |
|---|---|
| `./scripts/wizard.sh` | One-time setup: venv, dependencies, MCP registration |
| `./scripts/build_all.sh` | Rebuild DB from a Claude.ai export (run after each new export) |
| `./scripts/run_server.sh` | Start the MCP server manually (smoke check outside Claude Code) |
| `scripts/service/` | Watcher background-service templates: launchd plist (macOS), systemd user unit (Linux) — install instructions in each file's header |

```bash
./scripts/build_all.sh --help      # full options + steps
./scripts/wizard.sh --help         # prerequisites + what the wizard does
```

**Tests and standalone scripts:**
```bash
pytest                           # full suite (unit + integration)
pytest -m "not integration"      # fast local loop: skips real subprocess/lock tests
pytest -n auto                   # parallelize across cores (pip install pytest-xdist)
bash tests/check_docs.sh         # structural lint (versions, file paths)
python3 ingest_code_sessions.py  # incremental Claude Code session ingest
python3 ingest.py                # parse-only, no embedding (dry-run check)
python3 query.py "your query"    # ad-hoc CLI search (--top-k N, --db PATH)
python3 scripts/print_schema.py  # dump each MCP tool's input/output JSON schema
mcp dev server.py                # interactive MCP Inspector (browse + invoke tools)
```

## How the MCP server is actually used

The server registers three tools with Claude: `search_chat_history`, `get_nearby_context`,
and `get_conversation`. Claude Code loads a tool's schema lazily — only once that specific
tool is actually called in a session — so an unused tool costs nothing. Measured cost per
tool once loaded (via `/context`): `search_chat_history` ~517 tokens, `get_nearby_context`
~393, `get_conversation` ~283 (~1193 total if a session calls all three).

`search_chat_history` results are for orientation/ranking only — each hit's `text`
is a short preview, not the full chunk. Before treating anything from a hit as fact,
call `get_nearby_context` or `get_conversation` to pull the real reconstructed text.

**What triggers a search:**
Note that the tool description drives autonomous behavior.
The current description is reactive: Claude calls `search_chat_history` when
it notices it's about to re-derive something it suspects has been covered before.
In a narrow coding task it may never fire; in a design or planning conversation
it may fire more.

**The most reliable pattern:** ask explicitly.
> "Search the context bridge for [topic]."

This produces a direct, well-formed tool call rather than leaving query
construction to Claude's autonomous judgment. Semantic search rewards
descriptive phrases over single keywords — "what did we decide about chunking
strategy" retrieves better than "chunking".

**Current retrieval limitation:** `search_chat_history` has no locality signal.
A query from a `foo` session ranks `foo` sessions no higher than
sessions from `bar`, `baz`, or any other project. This is the Phase 3
gap (`current_project` parameter — see `PLAN.md`). Until Phase 3 is implemented,
cross-project noise is a known retrieval quality ceiling.

## Troubleshooting / FAQ

**The model download hangs or fails.**
fastembed downloads `~130 MB` on first run. If it times out, check your network
and retry. The cache lives at `~/.cache/fastembed/`.

**`build_all.sh` says "OOM" or crashes during embedding.**
Reduce `CONTEXT_BRIDGE_BATCH_SIZE` in `.env` (try `16` or `8`) and re-run.

**The MCP server isn't appearing in Claude Code.**
Run `claude mcp list` to verify registration, then restart Claude Code (exit & resume session).
The server list is read at session start. If it's missing, re-run `./scripts/wizard.sh`.

**`search_chat_history` returns nothing (or only irrelevant results).**
Run `./scripts/build_all.sh` first — the server needs a built `chat_memory.db`. If the
DB exists, try a more descriptive phrase ("what did we decide about X") rather
than a single keyword.

**Claude Code sessions aren't appearing in search.**
Run `python3 ingest_code_sessions.py` to ingest the latest sessions, then
restart the MCP server. This step is separate from the Claude.ai export build.

**I changed the embedding model and now search is broken.**
See "Changing the embedding model" under Configuration above.

## Notes / known constraints
- `chat_memory.db` and `data/` are gitignored — local build artifacts, not committed.