Skip to main content

PASR

Provenance-Aware Span Recall — a zero-setup context broker your coding agent calls as an MCP tool. It hands the model the few lines that answer the question, each with a file:line and the reason it was picked — and tells the agent when it asked the wrong tool.

PyPI Python CI License

pasr explain — one MCP call, 42,768 to 2,718 tokens, a receipt for every line

The problem

An agent working in a real repo has two bad options: read whole files and burn its context window on code that never mattered, or grep-and-guess and miss the file that held the answer. Either way, you cannot see what it looked at — no record, no line numbers, no reason.

What PASR does

Budgeted

You set a token ceiling; PASR never returns more, and it packs whole spans — never a truncated function. If the full file set already fits, you get it back unchanged.

a budget bar: 2,718 tokens kept under a 3,000-token ceiling, 282 free

Traceable

Every span carries file:line, a token count, its retrieval score, and why it was kept (bm25, symbol, active_window, …). A byte-stable receipt — of what was kept and what was dropped — lands on disk for every call.

anatomy of one returned span: where it is (file:line), what it costs (tokens), why it was kept (retrieval signals + score)

Honest

Each result is classified localized / trace / aggregation, with a confidence and advice ("aggregation-style question — read the files directly"). PASR tells the agent when it is the wrong tool.

two queries classified: an aggregation query routed to 'read the files directly', a localized query passed with confidence 0.68

Zero setup

No daemon, no vector database, no index to build, offline by default.

Install

Add to Cursor Add to VS Code

claude mcp add pasr -- uvx pasr-mcp --workspace .

Or paste this into your client's MCP config (Claude Desktop, Windsurf, Cline, Zed, …):

{ "mcpServers": { "pasr": { "command": "uvx", "args": ["pasr-mcp", "--workspace", "."] } } }

After that you never type pasr. Ask your agent a question the normal way — "how does redirect handling work here?", "what breaks if I change HTTPAdapter?" — and the model calls select_context / trace_dependencies itself instead of opening whole files.

Add PASR once: one block in the MCP config, then the agent calls select_context on its own — 2,718 tokens with a receipt instead of 42,768 across 12 files

Per-client setup notes: Claude Code · Cursor · Windsurf.

Without an agent: pip install pasr-mcp, then pasr explain "<question>" prints the same receipt the MCP tool returns. Five verbatim runs against pinned public repos are in examples/.

In one call

One localized question — "how are redirects resolved and followed" — against psf/requests (verbatim transcript):

PASR select_context agent reads the repo
input tokens 2 718 — 94% less 42 768
tool round trips 1 1 large read
provenance file:line + reason for all 10 spans none
wrong-tool signal localized, confidence 0.68, "looks complete"

The selection itself runs offline in ~0.3 s on this repo — no API call, no index build. (pasr explain prints selected in N ms to stderr; it is kept out of the receipt, which stays wall-clock-free and byte-stable.)

Why PASR, not the usual options

PASR repo-map
(aider)
embedding search
(claude-context, Cody)
grep / ripgrep MCP
Setup none none embedder + vector DB + index build none
Returns bodies + file:line + reason + score signatures, no bodies chunks, no reason keyword hits
Hard token budget never exceeded truncates top-k, no cap dumps everything
Deterministic yes — byte-identical ~ no (ANN + model drift) yes
Says "wrong tool for this" yes — routing + confidence no no no
Audit trail a receipt per call no no no
Dependency-closure trace forward + reverse (impact) no no no

On the offline bake-off (50 tasks, 10 repos, 6k-token budget, no API, no GPU), select_context ties a full repo-map on "how does this work" questions (0.84) using 10× less text — 5.7k tokens across 18 files vs the map's 46 files of signatures — and with map_tokens=1200 it matches repo-map overall (0.90) at 100% critical-file coverage while still carrying real code. Full table: docs/competitors-benchmark.md.

Does the model actually answer better?

A 50-task, 10-repo evaluation — a real model answering from only what each arm supplies, a second model judging:

  • select_context 0.48 task success at 5.8k context tokens, vs a 59k-token whole-repo dump's 0.38+0.10 on paired success (pasr_fallback +0.12).
  • Both clear the −0.05 non-inferiority margin on the point estimate; the 95% CI still crosses it at n = 50.
  • PASR gets the answer's file into context 46 / 50, vs the dump's 33 / 50.
  • An agent's own grep + read-six-files scores 0.52 — but at 4× the tokens, 6 round trips, and a 30% critical-file miss.

A bounded efficiency result, not a superiority claim. Pre-registered, with the supporting runs: eval/RESULTS.md · narrative: docs/blog/what-worked.md.

How it works

query + file globs
  → discover safe workspace files, tokenize, line-aligned chunks
  → lossless-under-budget check: does the whole thing already fit? return it
  → candidates:  BM25 (Okapi)  +  lexical-anchor coverage  +  tree-sitter symbols
                 +  optional sub-word / MiniLM semantic scorer
  → fuse by reciprocal-rank fusion            score(s) = Σ_r  1 / (k + rank_r(s)),  k = 60
  → reserve an active window (prefix + tail of the likely answer region)
  → hard-budget pack (knapsack):  maximise Σ score(s)   s.t.   Σ tokens(s) ≤ budget
  → classify the query, score confidence, write the receipt
  → return spans + provenance + token accounting + advice

RRF needs no score calibration across the rankers — only their rank orders — so BM25, symbol hits, and the semantic scorer combine without tuning weights. The pack is whole spans only, dependency-ordered.

MCP tools

Tool Purpose
select_context budgeted, provenance-tracked slice for a query — plus map_tokens (a query-ranked symbol-index header, carved out of the budget) and trace= (fold a symbol's dependency closure into the same slice)
trace_dependencies deterministic def/reference closure for a symbol (Python, JS/TS); direction="callers" reverses it for impact analysis
explain_selection return the stored receipt for a prior selection
expand_context re-run a prior selection once with a larger budget

CLI

pasr explain "how is the request rate limited"        # run a selection, print the receipt
pasr trace enforce_per_user_request_quota src/        # a symbol's dependency closure
pasr trace HTTPAdapter src/ --callers                 # who calls it — impact analysis
pasr pack auth "session + login + token" src/auth/    # save a committable Context Pack
pasr review --staged src/                             # touched defs + the callers they affect
pasr context --issue "$(cat issue.txt)" src/ \        # headless slice for CI / agents
  --format text --metrics-file metrics.json
pasr report --price-per-mtok 3                        # tokens / round trips / $ saved so far

The path is optional everywhere — with none, PASR scans the whole workspace (.gitignore-aware). Pass a directory or globs (src/, lib/ "**/*.py") only to scope it tighter or run faster.

Receipts land in .pasr/receipts/<id>.{json,md} (gitignored) — a byte-stable record of what PASR handed the model and what it dropped. A usage ledger accrues in .pasr/ledger.jsonl; pasr report turns it into "N fewer tokens across M calls, R round trips saved". Context Packs land in .pasr/packs/ (committable) — a named, warm-start slice the whole team loads with select_context(pack="auth"). For CI there is a composite GitHub Action — see docs/ci.md.

Capability boundary (from the research)

  • Strong: deterministic dependency / variable-trace closure — large token cuts, quality preserved or improved.
  • Bounded positive: localized document / code QA — meaningfully fewer model input tokens and lower latency at parity quality.
  • Do not claim: global aggregation, repo-wide code completion, lexical-mismatch position robustness. PASR classifies these and says so.

Docs

This productises the frozen researchv2 study (model-external context optimization); a comparative write-up is in preparation.

Development

python -m venv .venv && . .venv/bin/activate   # or .venv\Scripts\Activate.ps1
pip install -e ".[dev]"
pytest -q

The pure-logic core imports no torch / transformers (and no mcp SDK — that loads only under pasr.mcp):

python -c "import pasr.pipeline, sys; assert not {'torch','transformers'} & set(sys.modules)"

License

Apache-2.0.

Download files

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

Source Distribution

pasr_mcp-0.2.0.tar.gz (96.5 kB view details)

Uploaded Source

Built Distribution

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

pasr_mcp-0.2.0-py3-none-any.whl (76.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pasr_mcp-0.2.0.tar.gz
  • Upload date:
  • Size: 96.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.10

File hashes

Hashes for pasr_mcp-0.2.0.tar.gz
Algorithm Hash digest
SHA256 30f57341c78ad370a340c3ff1988e5c92b2ee1110240930d4d8b94898bb068e1
MD5 093d884baa31bc7bd9128696619e5b70
BLAKE2b-256 1cb2d910d9323bdc98f19cdadfbdf49f2967cf17498115758edd1220467eeaa1

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pasr_mcp-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 76.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.10

File hashes

Hashes for pasr_mcp-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 43b255ce6747f54f798956b4dbd3e1d521006242466e4a6ffb20eb1c3ced0e5a
MD5 8dbed4bb7a23c334d185b8a869a4e6af
BLAKE2b-256 9de00abff899b02796118c35aa751dff8d27af7b0c52046daec1a4a90b074404

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.1

2 files

This release

0.2.0 This release

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