Read once, never again — self-describing files so AI agents stop re-parsing.
Project description
donotreadagain (dnr)
Read once, never again. Embed a faithful, signed transcript into each expensive-to-parse file's own metadata, so AI agents stop re-OCR/re-parsing the same PDF, image, scan, spreadsheet, or audio every time.
The problem
AI agents re-parse the same file every time they touch it — re-OCR a scan, re-run vision on a screenshot, re-transcribe an audio clip, re-extract a PDF. It's slow, it burns tokens and model calls, and it's non-deterministic. In repeat-access corpora (legal, research, compliance) the same documents get read dozens of times; with multi-agent setups every agent re-parses independently. The waste compounds exactly where it hurts.
The idea
dnr is the cache/trust/index layer for expensive reads. A local extractor, local ASR model, or the calling AI agent reads a file once; dnr stores the resulting transcript + structured metadata as a signed JSON record, preferably inside the file's own native metadata slot. The file becomes self-describing. Any agent that opens it later reads the cached transcript instead of re-parsing. A per-folder SQLite + FTS5 index makes a whole folder searchable without opening anything.
The second view is the win:
| first view (re-parse) | second view (cached) | |
|---|---|---|
| born-digital PDF | local text extraction (PyMuPDF→pypdf) | ~60 ms — no PDF parse |
| image / scan / audio | a vision / Whisper model call | a few ms of text — no model at all |
…and the cache is trustworthy: a record is used only if it's signed by a trusted key and its content_hash still matches the file, so "fast" never means "stale or forged."
Demo
$ dnr ingest contract.pdf # transcribe once → sign → embed in the file
ingested contract.pdf [in-file]
method=text-extract transcriber=pymupdf
signed key_id=ce6d170a497238f7
$ dnr read contract.pdf # later (or from any agent): verified cache hit — no re-parsing
LOAN AGREEMENT
Lender: Acme Capital LLC
Borrower: Jordan Smith
Principal: USD 1,200,000
...
$ dnr index ./contracts
$ dnr query ./contracts --match damages --context 40 # search a whole folder, no files opened
contract.pdf
… Principal: USD 1,200,000 Maturity: 2026-12-31 Damages clause: section 7.
The transcript lives inside contract.pdf — move it, email it, hand it to another agent, and the cached transcript travels with it.
Quickstart
Recommended install:
pipx install donotreadagain
dnr --version
# one-off/fallback when installing is not available:
uvx --from donotreadagain dnr <cmd>
# audio ASR:
pipx inject donotreadagain faster-whisper # ffmpeg may also be needed for decoding
dnr ingest report.pdf # extract once (local) → sign → embed in the file
dnr backfill ./case-folder # folder pass: local-provider files now, agent/vision worklist after
dnr read report.pdf # print the cached transcript (verified), or fall back
dnr index ./case-folder # build .dnr.db
dnr status ./case-folder --pending # honest usable/pending/repair coverage
dnr query ./case-folder --match "손해배상" --tag 가압류 --since 2025-01-01
For a scan / image / anything you must look at, the agent transcribes it and records the result:
dnr record scan.png --transcript-file t.md --method vision --transcriber <your-model>
How it fits together
File = canonical truth Index .dnr.db = derived, regenerable
┌────────────────────────────┐ harvest ┌────────────────────────────┐
│ signed dnr record │ ───────▶ │ fixed table + FTS5 search │
│ content_hash · transcript │ │ path · tags · transcript … │
│ provenance · fields · sig │ └────────────────────────────┘
└────────────────────────────┘ ▲ query via sqlite3 — dnr CLI optional for reads
▲ transcribe · sign · embed once (expensive)
Where the record lives (no sidecar files):
- In-file for formats with a metadata slot — PDF→XMP, MP3→ID3, M4A/MP4/MOV→MP4 freeform atom, FLAC/OGG/OPUS→Vorbis/Opus comments, PNG→iTXt, JPEG→APP segment. Pixels/bytes-of-content untouched (
content_hashinvariant), so the transcript travels with the file (move it, email it — it's still there). - db-only in the folder's
.dnr.dbfor formats with no slot yet (docx, …), or via--no-embedwhen the user explicitly wants byte-identical originals / no file modification. db-only records are folder-scoped; if the source file changes, the stale record is removed and the file must be re-ingested/re-recorded. - Nothing for already-readable text (
.txt/.md/.csv) — an agent just reads it.
Current format support:
| Format | Transcription | Record storage | Status |
|---|---|---|---|
local text layer (PyMuPDF first, pypdf fallback) or agent vision for scans |
XMP in-file | partial | |
| PNG / JPEG | agent-supplied vision transcript | PNG iTXt / JPEG APP in-file | implemented |
| HEIC / HEIF | agent-supplied vision transcript; optional pillow-heif hash |
db-only | partial |
| MP3 / WAV / M4A / FLAC / OGG / OPUS | local Whisper provider via donotreadagain[audio], if installed |
in-file except WAV db-only | partial |
| DOCX | local python-docx text extraction |
db-only | implemented |
| XLSX | local openpyxl sheet extraction |
db-only | implemented |
| MP4 / MOV video | agent-supplied transcript/ASR+vision | MP4 freeform in-file | partial |
| PPTX / other office/media | planned providers or agent-supplied transcript | db-only until carriers land | planned |
Using it
- Read (consumer):
dnr read <file>returns the cached transcript only if it's present, trusted, and still matches (self-validating — a changed file silently misses). No dnr tool? An agent can read.dnr.dbdirectly with ambientsqlite3(the db's_dnr_readmetable self-describes). - Transcribe (producer):
dnr ingest(local: PyMuPDF→pypdf / python-docx / openpyxl / optional faster-whisper) ordnr record(agent supplies a vision/OCR transcript). dnr is an opportunistic cache: do this when the current task already requires reading/parsing that file, not just because a folder has pending files. If a needed file's cached transcript is empty/garbled/unusable, repair that file immediately; ask only before expanding into whole-folder OCR/searchability work. - Backfill a folder:
dnr backfill <folder>(alsodnr ingest <folder>) ingests locally-processable files in one pass, skips already-readable text, and prints a worklist for images/scans/videos or low-quality results that need agent/vision repair. - Query a folder:
dnr query <folder>combines--match(FTS, Korean/CJK ok) ∩--tag a,b∩--since/--until∩ restricted--whereover fixed columns; plus--any(OR sweep),--dedup,--context(KWIC),--format json. Save composed queries with--save/--use; accumulate labels withdnr tag. - Agents onboard once: point an agent at a dnr folder and it fetches SKILL.md once — then it knows dnr everywhere. Recommended install is
pipx install donotreadagain; one-off fallback isuvx --from donotreadagain dnr ....dnr initjust ensures a signing key by default; to persist the bootstrap in an agent instruction file, rundnr init --agent-file AGENTS.md(or--agent-file CLAUDE.md). To make dnr a global agent habit, rundnr init --global-agent; the skill asks agents to do this on first use when supported.
Design principles
- dnr is the deterministic substrate; the agent is the intelligence. dnr does verifiable primitives (hash, sign, full-text/structured query); it never infers metadata (dates, parties, topics) or does fuzzy semantic search — that's the agent's job. Set metadata explicitly with
dnr tag/dnr date. - File = truth, index = regenerable cache. Delete
.dnr.dband rebuild it from the files anytime. - Transcriber-agnostic. dnr ships a contract (the verbatim guide) + a trust layer, not a model. Fidelity is the transcriber's; provenance is recorded so a consumer can apply its own quality policy (
trusted ≠ faithful).
Status & honest limits
v0.2 early release. Published on PyPI as donotreadagain; the recommended path is pipx install donotreadagain. uvx remains a one-off/fallback path, but it still requires uv and can be slower than a normal install for repeated use. Standalone binaries remain a future packaging option for Python-less environments. Works today for repeat-access corpora; validated by real-corpus dogfooding. Known limits we're explicit about:
- Adoption is the real lever. The value compounds when agents know dnr (a skill, eventually native support) — not from the tool alone.
trusted ≠ faithful. A signature proves who made it + that it matches the file, not that the transcription is accurate. Low-quality/garbled transcripts are flagged (dnr status), not silently trusted.- Coverage is still growing. PDF/PNG/JPEG/HEIC/DOCX/XLSX and common audio containers are useful today; OOXML in-file carriers, more video containers, pre-query auto-scan, and larger-corpus concurrency are still roadmap work.
- Benchmarks are early. The README numbers are illustrative dogfood timings; see BENCHMARKS.md and experiments/content-hash-invariance for the current proof/measurement status. A broader latency/token benchmark remains a release-readiness item.
- Python is currently required. Use
pipxfor the cleanest install; a standalone binary for Python-less environments is future work.
See vision.md (design) · spec/dnr-0.1.md (spec) · SECURITY.md (threat model) · qna.md (settled design decisions) · MILESTONES.md (roadmap).
Development
git clone https://github.com/melodysdreamj/donotreadagain
cd donotreadagain
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest # the suite is green and fast
Contributions welcome — see CONTRIBUTING.md. Release automation is documented in RELEASING.md.
License
MIT © 2026 june lee
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 donotreadagain-0.2.2.tar.gz.
File metadata
- Download URL: donotreadagain-0.2.2.tar.gz
- Upload date:
- Size: 93.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
087d53608ae1359ffe85a3d4ad0f92f8909495ad0f33313e154b01942b8412c6
|
|
| MD5 |
f22906cab643b024dbdc6a9aff614e8c
|
|
| BLAKE2b-256 |
e92d2d8756a9d09a5bbd6941ee8d5b6c53d696e61ebc31446aa1addb3602a98f
|
Provenance
The following attestation bundles were made for donotreadagain-0.2.2.tar.gz:
Publisher:
publish.yml on melodysdreamj/donotreadagain
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
donotreadagain-0.2.2.tar.gz -
Subject digest:
087d53608ae1359ffe85a3d4ad0f92f8909495ad0f33313e154b01942b8412c6 - Sigstore transparency entry: 1895289017
- Sigstore integration time:
-
Permalink:
melodysdreamj/donotreadagain@5c94a605c0ab6542ef2e0a5bc5c834dc768ade6b -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/melodysdreamj
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5c94a605c0ab6542ef2e0a5bc5c834dc768ade6b -
Trigger Event:
release
-
Statement type:
File details
Details for the file donotreadagain-0.2.2-py3-none-any.whl.
File metadata
- Download URL: donotreadagain-0.2.2-py3-none-any.whl
- Upload date:
- Size: 50.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f45d48777adbf0fd2a362df569b8e740f72cd172ddfdccc18d1c212e1c3ddb8
|
|
| MD5 |
c08cfcd810eae5f099e258d26dac4a44
|
|
| BLAKE2b-256 |
c2168fc05d7c1819cd398c49ba1c23130ba1d24bcd7e909c33dd0f64e9e0a343
|
Provenance
The following attestation bundles were made for donotreadagain-0.2.2-py3-none-any.whl:
Publisher:
publish.yml on melodysdreamj/donotreadagain
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
donotreadagain-0.2.2-py3-none-any.whl -
Subject digest:
4f45d48777adbf0fd2a362df569b8e740f72cd172ddfdccc18d1c212e1c3ddb8 - Sigstore transparency entry: 1895289131
- Sigstore integration time:
-
Permalink:
melodysdreamj/donotreadagain@5c94a605c0ab6542ef2e0a5bc5c834dc768ade6b -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/melodysdreamj
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5c94a605c0ab6542ef2e0a5bc5c834dc768ade6b -
Trigger Event:
release
-
Statement type: