Catch missing, duplicated, unexpected, and out-of-order book photos before OCR.
RectoReady is a small offline CLI for solo book scanners, researchers, and small archives. Describe a left-to-right bound volume as physical leaves, then compare the expected shot sequence with a capture log and the real files on disk. RectoReady emits a reviewable report and, only when every check passes, a canonical rename manifest. It never renames or modifies source captures.
6 physical leaves + 1 opened foldout
↓ rectoready plan
8 exact capture shots
↓ rectoready reconcile
complete rename.csv OR RR101–RR107 repairs
RectoReady is deliberately not an OCR engine, image editor, scanner driver, or institutional workflow server. Its narrow job is to prove that the physical capture sequence and the files you actually have agree.
From a checkout of this repository:
python -m pip install .
rectoready plan examples/field-notes/manifest.json --out output/plan
rectoready reconcile examples/field-notes/manifest.json examples/field-notes/complete.csv --capture-root examples/field-notes/captures --out output/reconcileExpected result:
Planned 8 shots in plan.
Reconciliation complete: 8 shots mapped in reconcile.
Open output/plan/report.html to follow the physical capture order, or
output/reconcile/report.html to review completion. The successful rename
manifest is explicit and advisory:
source,target,shot_id
capture-0001.pgm,field-notes-1912__shot-0001.pgm,shot-0001
capture-0002.pgm,field-notes-1912__shot-0002.pgm,shot-0002Python 3.11 through 3.14 is supported. The v0.1.0 GitHub Release provides a pure-Python wheel, source distribution, standalone zipapp, and the example bundle. Install the wheel directly from the Release:
python -m pip install https://github.com/KanadeK/rectoready/releases/download/v0.1.0/rectoready-0.1.0-py3-none-any.whl
rectoready --versionRectoReady has no runtime dependencies and makes no network calls. v0.1.0 is distributed through GitHub Releases, not PyPI.
- A researcher photographing a bound notebook with a camera or book cradle.
- A volunteer digitizing a small local-history volume before cleanup and OCR.
- A small archive that wants an inspectable CSV/JSON handoff without deploying a database or workflow platform.
The key input is a physical-leaf manifest, not page-number guesses or image
recognition. For leaves L1 … Ln, RectoReady plans L1.recto, each interior
Li.verso + Li+1.recto spread, and Ln.verso. Dedicated captures such as an
opened foldout are inserted immediately after their referenced surface.
rectoready init --volume-id my-volume --leaves 24 --output volume.jsoninit refuses to overwrite an existing file. Edit the generated labels and
add any dedicated extra captures before planning.
rectoready plan volume.json --out output/planThis creates:
plan.json— structured expected shots;shot-list.csv— one scanner-friendly row per item and position;report.html— a self-contained review page.
Create a UTF-8 CSV with exactly two columns:
filename,shot_id
IMG_1001.pgm,shot-0001
IMG_1002.pgm,shot-0002Then run:
rectoready reconcile volume.json captures.csv --capture-root captures --out output/reconcileThe command checks expected shots, row order, reused filenames, path
containment, regular-file presence, and non-empty files. It always writes
reconcile.json, rename.csv, and report.html for a well-formed run. If any
finding exists, rename.csv contains only its header so a partial mapping
cannot be mistaken for a complete one.
Try a real failure path:
rectoready reconcile examples/field-notes/manifest.json examples/field-notes/missing-shot.csv --capture-root examples/field-notes/captures --out output/missingIt exits 1, prints RR101 MISSING_SHOT, and gives a concrete repair. Invalid
JSON/CSV, unsafe paths, inaccessible inputs, and output conflicts exit 2 with
an input error and Fix: line. A complete reconciliation exits 0.
| Code | Name | Meaning |
|---|---|---|
RR101 |
MISSING_SHOT |
An expected shot has no capture row. |
RR102 |
DUPLICATE_SHOT |
An expected shot is named more than once. |
RR103 |
UNEXPECTED_SHOT |
A row names a shot outside this plan. |
RR104 |
DUPLICATE_FILE |
The same filename is reused. |
RR105 |
OUT_OF_ORDER |
Known shots do not follow plan order. |
RR106 |
MISSING_FILE |
A path is absent or not a regular file. |
RR107 |
EMPTY_FILE |
A capture file has zero bytes. |
The complete contracts are in formats and repairs.
- Only left-to-right bound-volume sequencing is modeled.
- The declared physical leaf structure is trusted; printed page numbers are not recognized automatically.
- File checks prove structure, presence, and non-emptiness—not image decoding, focus, resolution, color, crop, or archival quality.
- The rename CSV is advisory. v0.1.0 never applies it.
- v0.1.0 has no GUI, OCR, ML, scanner control, database, cloud service, METS/ALTO, or IIIF integration.
output file ... already exists— choose a new--outdirectory or move the previous artifacts; outputs are never overwritten.must stay inside capture root— use a relative filename with no drive, leading slash, or..segment.RR106 MISSING_FILE— confirm the CSV filename is relative to--capture-rootand restore the file there.RR105 OUT_OF_ORDER— reorder CSV data rows to matchshot-list.csv.- Exit
1means the report is valid and contains findings; exit2means RectoReady could not make a trustworthy report.
See the Chinese quick start and the full troubleshooting guide.
The project uses uv for a locked development environment:
uv sync --locked
uv run --no-sync python scripts/check.pyThe single gate verifies formatting, lint, strict types, branch-covered tests, real success/boundary/failure examples, package build, clean wheel install, installed console entry, README commands, and the standalone zipapp. CI invokes the same command.
Architecture rationale and the executable contract live in ADR-0001 and docs/spec.md. Contributions are welcome under CONTRIBUTING.md; security reports follow SECURITY.md.
MIT © 2026 KanadeK.