Preflight router that picks the cheapest faithful path (text, OCR, or vision) before a document reaches a multimodal LLM.
Project description
LocalContextRouter
Decide locally how each page of a document should reach a multimodal model: as extracted text, on-device OCR, or a rendered image. That keeps you from paying for vision tokens on pages that are only text.
A multimodal model reads a PDF by pulling its text and rendering every page to an image, then billing for both. On a text page that image runs roughly 1,300 to 4,800 tokens while the same page as plain text is 400 to 800. For a text-dominant document that is several times the cost for nothing extra. LocalContextRouter does the cheap work on your machine first and tells you what each page actually needs.
It does not call a model. It returns a per-page decision and the text to send; your application still makes the call.
How it decides
For each page:
- A usable text layer that is mostly prose: use the extracted text.
- A text layer dominated by a table, chart, or diagram: send the page as an image, where the layout carries the meaning.
- No usable text, such as a scan or a photo: recognize it on-device with Apple's Vision framework.
The result also reports how many tokens you saved against sending every page as an image.
Install
pip install localcontextrouter
macOS only. The wheel bundles a universal (Apple Silicon and Intel) OCR binary, so text recognition works with no extra setup.
Command line
localctx invoice.pdf
localctx invoice.pdf --json
localctx scan.png
localctx invoice.pdf prints each page, the source chosen for it, and the
tokens saved:
Document: invoice.pdf (3 pages)
Tokens saved vs sending every page as an image: 3085
Page 1 [text]
ACME Corp, Invoice #4471 ...
Page 2 [vision]
Quarterly results by segment ...
Page 3 [ocr]
SCANNED RECEIPT TOTAL 42.00
Add --vision-dir DIR to render the pages that should go to the model as images
into DIR; their paths are then listed in the output and the JSON.
In code
from localcontextrouter import route_pdf, Source
result = route_pdf("invoice.pdf")
for page in result.pages:
if page.source is Source.VISION:
send_image(page.index) # the page's meaning is visual
else:
send_text(page.text) # extracted or recognized text
print(result.tokens_saved)
Every page also carries an estimate of its cost both ways, as
page.tokens.text_tokens and page.tokens.image_tokens.
As an agent skill
local-context-router is an Agent Skill in the open SKILL.md format, so it
works in Claude Code and other compatible agents. It lives in this repository
under .claude/skills/local-context-router; copy that folder into your agent's
skills directory:
cp -r .claude/skills/local-context-router ~/.claude/skills/
With the package installed, the agent runs the preflight on any PDF or image you share, then uses the text for the cheap pages and attaches images only for the visual ones.
Requirements and scope
- macOS 11 or newer. Recognition uses the Apple Vision framework and needs a normal macOS graphics environment; it will not run inside a headless sandbox that lacks one.
- Python 3.10 or newer.
- The scope is per-page routing, on-device OCR, and a token estimate. Retrieval over very large documents is out of scope.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file localcontextrouter-0.1.0.tar.gz.
File metadata
- Download URL: localcontextrouter-0.1.0.tar.gz
- Upload date:
- Size: 26.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ef1e6d6fcedeab7c6b811d1c5fac3bc4462c28f7e3a9156e77904574d920541
|
|
| MD5 |
0a662b7dc0aa895622787fbb8d0d73cf
|
|
| BLAKE2b-256 |
6f645291963fb63c02a11cf3c7587aebc2aadef05689bb019d84f1459fb30f83
|
Provenance
The following attestation bundles were made for localcontextrouter-0.1.0.tar.gz:
Publisher:
release.yml on sid732/LocalContextRouter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
localcontextrouter-0.1.0.tar.gz -
Subject digest:
1ef1e6d6fcedeab7c6b811d1c5fac3bc4462c28f7e3a9156e77904574d920541 - Sigstore transparency entry: 1920306220
- Sigstore integration time:
-
Permalink:
sid732/LocalContextRouter@aeddfe89b4f528c48a988ff2cf24e7e2f5b692a1 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sid732
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@aeddfe89b4f528c48a988ff2cf24e7e2f5b692a1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file localcontextrouter-0.1.0-py3-none-macosx_11_0_universal2.whl.
File metadata
- Download URL: localcontextrouter-0.1.0-py3-none-macosx_11_0_universal2.whl
- Upload date:
- Size: 112.9 kB
- Tags: Python 3, macOS 11.0+ universal2 (ARM64, x86-64)
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c38fb5e92bb958135ef82edac46fa079c1e976887bd546c2b928698dda4a7848
|
|
| MD5 |
dfe9df85f7bd859ae77a1941790533cc
|
|
| BLAKE2b-256 |
dd6a99f150f73db1b784c2b7d0c33746c6787d771028c03b8ac38d990238ee3a
|
Provenance
The following attestation bundles were made for localcontextrouter-0.1.0-py3-none-macosx_11_0_universal2.whl:
Publisher:
release.yml on sid732/LocalContextRouter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
localcontextrouter-0.1.0-py3-none-macosx_11_0_universal2.whl -
Subject digest:
c38fb5e92bb958135ef82edac46fa079c1e976887bd546c2b928698dda4a7848 - Sigstore transparency entry: 1920306337
- Sigstore integration time:
-
Permalink:
sid732/LocalContextRouter@aeddfe89b4f528c48a988ff2cf24e7e2f5b692a1 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sid732
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@aeddfe89b4f528c48a988ff2cf24e7e2f5b692a1 -
Trigger Event:
push
-
Statement type: