Skip to main content

ContextPull

Website: https://mi2arun.github.io/contextpull/ · demo · docs

Pull, don't push. ContextPull turns a folder of documents into something an LLM agent can pull from the way Claude Code pulls from a codebase: a small index that is always in context, and five tools that return exact sections on demand. The model never receives content it did not ask for.

Zero runtime dependencies. One SQLite file. Works offline.

ContextPull ships with a companion, ragbisect (formerly stagewise): a neutral benchmark harness that builds an eval set from your corpus and scores ContextPull next to bm25, dense and hybrid pipelines. Two names, one project, kept apart so the measurement stays independent of the thing it measures.

Status

M1 to M3 are built: store, ingest, the five operations, CLI, conformance suite, MCP server, Claude Code integration, LLM summaries, protocol client examples, ragbisect adapters, and a TypeScript reader and server. See the roadmap.

Measured

uv documentation, 603 sections, 221 self-generated questions, recall@5, from docs/testing.md:

config recall@5 ms/q model tokens/q
hybrid push (dense + bm25) 0.964 69 0
bm25 push 0.923 5 0
pull, Claude Code (10-question sample) 1.000 26,565 86,656
pull, gpt-5.4-mini with reasoning off 0.615 16,023 10,891

A strong agent reads the right section every time; a small no-reasoning model reads the right section when it reads (NDCG 0.96 given a hit) but misses the gold section on 38% of questions. Push retrieval is nearly free per query; pull costs tens of thousands of tokens. Both facts are in the table on purpose. The model's own searches surfaced the gold section on 88% of a sample, so most of the gap is snippets being answered from rather than read; a stricter prompt did not change that. An earlier version of this table showed 0.045 for the small model; that number came from a threading bug in the benchmark adapter and is retracted in docs/testing.md.

Try it

Fastest: ./scripts/demo.sh ingests the bundled fixture corpus and walks through index, search, read and grep, then prints the exact claude mcp add line. ./scripts/demo.sh ./your-docs does the same on your own folder.

uv tool install contextpull            # or: pip install contextpull   (PyPI: contextpull 0.1.0)
contextpull ingest ./docs              # writes .contextpull/store.sqlite
contextpull index                      # the always-in-context table of contents
contextpull search "refund window" --in policy-2025.md
contextpull read policy-2025.md#3 --context 1
contextpull grep TX-4419
contextpull neighbours specs.md#1
contextpull export-chunks > chunks.jsonl   # ragbisect-compatible sections

In Claude Code

claude mcp add contextpull -- uvx --from "contextpull[mcp]" contextpull serve ./docs

The server ingests ./docs into ./docs/.contextpull/store.sqlite, puts the index into its instructions so it is always in context, and exposes the five tools. Ask a question; the trace shows search, then read, then an answer with [path.md#3] citations. contextpull claude-md prints a CLAUDE.md snippet if you want to tell the model about it explicitly. Add --summarizer openai:gpt-5.4-mini for model-written one-line summaries in the index (cached by document hash).

Any other MCP host works the same way; see examples/clients/ for TypeScript, Go and Java protocol clients and examples/direct_api_loop.py for using the tools straight from a model API with no server.

More

uv sync --extra pdf                                             # PDFs: headings inferred from font size
uv run contextpull ingest ./docs --embed-model openai:text-embedding-3-small   # enables: search --mode hybrid
uv run contextpull serve ./docs --transport http --port 8765    # streamable HTTP at /mcp for a shared read-only server

As a library

Embedding it in your own product, with access control and air-gap notes: docs/embedding.md and examples/embed_with_acl.py.

from contextpull import Store, Ops

with Store.open(".contextpull/store.sqlite") as store:
    ops = Ops(store)
    print(ops.index())
    hits = ops.search("refund window", in_=["policy-2024.md", "policy-2025.md"]).hits
    for h in hits:
        print(h.id, h.heading_path, h.snippet)
    section = ops.read(hits[0].id).section

Tool definitions for any model API are in contextpull.tools.TOOLS (Anthropic shape) and openai_tools(); tools.json at the repo root is the same thing for other languages.

How it works

  1. Ingest parses Markdown, text, docx, xlsx, pptx and (with the pdf extra) PDF into headings, paragraphs, tables and code, and cuts heading-aware sections with stable ids like policy-2025.md#3. Tables and code are never split mid-block; long tables are split by rows and every part carries the header. Unchanged files are skipped on re-ingest.
  2. Store is one SQLite file with an FTS5 index whose tokenizer keeps identifiers whole (--no-cache, UV_CACHE_DIR, TX-4419, 3.12).
  3. Index is a token-budgeted table of contents, one line per document, delivered into the model's context. It goes hierarchical when a corpus is too large for the budget.
  4. Tools: index, search (ids and snippets, never bodies), read (verbatim), grep (exact matches), neighbours (the header row, the next clause).

Node

sdk/typescript/ is a store-native reader and MCP server in TypeScript over better-sqlite3: open the same store file, no Python at query time. Published to npm as contextpull.

npx contextpull serve /path/store.sqlite                   # npm: contextpull 0.1.0
claude mcp add contextpull -- npx -y contextpull serve /path/store.sqlite

It passes the same conformance suite as the Python reference and returns identical results over MCP. Ingest stays in Python (npx contextpull ingest delegates to uvx contextpull ingest).

Go

sdk/go/ is a store-native reader and a single static binary server, pure Go, no cgo: the shape for a shared read-only deployment.

cd sdk/go && go build -o contextpull-server ./cmd/contextpull-server
./contextpull-server serve /data/store.sqlite --http 0.0.0.0:8765    # or without --http for stdio

Same conformance suite, identical results to Python over MCP.

Other languages

The store file is the contract. docs/store-format.md says what a reader must do; conformance/ holds a fixture corpus, its store and expected results. An SDK in any language is done when check passes. See the SDK plan.

Docs

Start at docs/README.md: architecture, design, system design, tool reference, evaluation, roadmap, decision records.

Measured with ragbisect, which lives next door.

Download files

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

Source Distribution

contextpull-0.2.0.tar.gz (281.4 kB view details)

Uploaded Source

Built Distribution

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

contextpull-0.2.0-py3-none-any.whl (46.9 kB view details)

Uploaded Python 3

File details

Details for the file contextpull-0.2.0.tar.gz.

File metadata

  • Download URL: contextpull-0.2.0.tar.gz
  • Upload date:
  • Size: 281.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for contextpull-0.2.0.tar.gz
Algorithm Hash digest
SHA256 89a02eabf39ff0b8893f3a89b4c8d3dff9ef1cd585487f112bb9d73ca48f2ccb
MD5 b52869ac85a1a0f0727d4b5d0efcbf01
BLAKE2b-256 9373f2e7abc3d8b7dceb98ea2b79bed2a5717000cbd99f452b8fac1943d7b95f

See more details on using hashes here.

Provenance

The following attestation bundles were made for contextpull-0.2.0.tar.gz:

Publisher: publish-pypi.yml on mi2arun/contextpull

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

File details

Details for the file contextpull-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: contextpull-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 46.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for contextpull-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 83738d6d156ac9cb5c07793620ee22c934a931d245903ba26f4f6a6330799d0e
MD5 061febe7e9424de19822bbf44516cd60
BLAKE2b-256 b532e70dc76f859127135a809dfb31af28cc902f50c225e7c4cc2c282e9f417a

See more details on using hashes here.

Provenance

The following attestation bundles were made for contextpull-0.2.0-py3-none-any.whl:

Publisher: publish-pypi.yml on mi2arun/contextpull

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

Release history Release notifications | RSS feed

0.2.1

2 files

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page