Skip to main content

amagi-binder

Turn a folder of exhibits into one court-ready PDF. You list the exhibits in a short YAML or CSV file. amagi-binder Bates-stamps every page and adds a slip sheet before each exhibit. It builds a table of contents with clickable links, bookmarks every exhibit, and writes a CSV log of which Bates numbers went where. Built for solo attorneys, small firms and people representing themselves.

demo

Contents page, exhibit slip sheet, and a stamped landscape page

You don't need Acrobat Pro or a litigation suite for this. Everything runs on your machine. Files are never uploaded, and you don't need an account or an API key.

Install

pipx install amagi-binder

Needs Python 3.9 or newer. It takes PDF, JPG, PNG and TIFF files.

Usage

The examples folder holds a made-up breach-of-warranty case with six exhibits: a contract, a purchase order, an email thread, a scanned landscape service log, a photo and a demand letter. The check and build commands below run from that folder.

1. Start an index from a folder

Here the same six files sit in a folder called my_exhibits (this run was on Windows, so the paths print with backslashes):

$ amagi-binder init my_exhibits/ --title "Plaintiff's Trial Exhibits"
wrote my_exhibits\index.yaml with 6 exhibits (sorted by file name). Edit it, then run:
  amagi-binder build my_exhibits\index.yaml -o binder.pdf

Files are sorted the way a person would sort them (2_ before 10_), and each title is a guess from the file name:

# amagi-binder index. Edit titles, dates and order, then run:
#   amagi-binder build <this file> -o binder.pdf
title: "Plaintiff's Trial Exhibits"
caption: ""          # e.g. "Doe v. Roe, Case No. 1:26-cv-00001"
bates:
  prefix: ""         # e.g. "DOE" or "DOE_"
  start: 1
  digits: 6
labels: numbers      # or: letters
exhibits:
  - file: "01_supply_agreement.pdf"
    title: "Supply agreement"
    date: ""
  - file: "02_purchase_order.pdf"
    title: "Purchase order"
    date: ""
...

Fix the titles, add dates, and put the exhibits in the order you want. The index order is the binder order. An exhibit can also take a fixed label (7A), a description for its slip sheet, a pages range ("1-3,5"), or several files that belong together, like an email and its attachment. See examples/riverside/index.yaml for a filled-in index.

Prefer a spreadsheet? Use a CSV with the columns file,label,title,date,description,pages instead (example).

2. Check the plan

check reads every file and shows what each exhibit will get. It writes nothing.

$ amagi-binder check riverside/index.yaml
Exhibit  Pages  Bates range            Binder pages  Title
1        3      RBK000001 - RBK000003  2-5           Equipment Supply and Service Agreement
2        1      RBK000004              6-7           Purchase Order RB-2025-014
3        1      RBK000005              8-9           Emails between D. Whitfield and P. Osterm...
4        1      RBK000006              10-11         Northgate service log for the DX-40
5        1      RBK000007              12-13         Photo of the oven display reading 547 F a...
6        1      RBK000008              14-15         Letter demanding return and refund under...

6 exhibits, 15 binder pages, 1 contents page. Next Bates number: RBK000009
OK

It stops with exit code 1 on a missing file, a password-protected or broken PDF, a bad page range, or two exhibits with the same label. It warns about files in the folder that the index leaves out. --json prints the same plan for scripts.

3. Build the binder

$ amagi-binder build riverside/index.yaml -o binder.pdf
Exhibit  Pages  Bates range            Binder pages  Title
...
wrote binder.pdf (6 exhibits, 15 binder pages, 1 contents page. Next Bates number: RBK000009)
wrote binder_bates_log.csv

The sample output is in the repo: examples/binder.pdf and examples/binder_bates_log.csv.

What's in the PDF:

  • A table of contents listing each exhibit's label, title, date, page count, Bates range and binder page. Click a row to jump to that exhibit. Long lists run onto more pages.
  • A slip sheet before each exhibit, with the label in large type, the title, date, description, Bates range and case caption.
  • A Bates number on every exhibit page. By default it sits bottom-right, 0.3 inch from the edge, as the page appears on screen. Rotated scans and cropped pages are stamped in the right spot.
  • Bookmarks for every exhibit, with a sub-bookmark for each file when an exhibit has several.
  • Page labels, so the viewer's page box shows RBK000004 and you can type a Bates number to jump to it.

The log has one row per exhibit, with a SHA-256 hash of each source file so you can show later which version of a document you produced:

exhibit,title,date,files,pages,bates_begin,bates_end,binder_page_begin,binder_page_end,sha256
1,Equipment Supply and Service Agreement,"January 15, 2025",01_supply_agreement.pdf,3,RBK000001,RBK000003,2,5,11202a2a1919931129ebf405d27c836632364512c43c153dcb00ed10ceb555d0
2,Purchase Order RB-2025-014,"January 20, 2025",02_purchase_order.pdf,1,RBK000004,RBK000004,6,7,6f1df52cfad2f2fd28bb037cd13e5dfc283510f6144624fc678f9283d6e83d0c

Options

Flags override the index file:

$ amagi-binder build riverside/index.yaml -o binder.pdf --prefix DEF_ --start 1201 --legend CONFIDENTIAL --stamp-slips -q
wrote binder.pdf (6 exhibits, 15 binder pages, 1 contents page. Next Bates number: DEF_001215)
wrote binder_bates_log.csv
Flag What it does
--prefix, --start, --digits Bates format: DEF_001201
--legend TEXT A second stamp at bottom-left, such as CONFIDENTIAL
--exhibit-stamp Adds Exhibit 3, page 2 of 5 at bottom-center
--position, --font-size, --box Stamp placement, size, and a white box behind it
--stamp-slips Slip sheets get a Bates number too
--no-bates, --no-slips, --no-toc Leave parts out
--labels letters, --label-start N Exhibits A, B, C (after Z comes AA), or start at 12
--exhibit-word Tab Slip sheets say TAB instead of EXHIBIT
--paper letter|legal|a4 Size of slip sheets, contents pages and photo pages
--exhibits DIR Folder the file names are relative to, if the index lives elsewhere

Run the same index twice and you get a byte-identical PDF.

Exit codes: 0 ok, 1 the index has problems, 2 usage error.

Use it from Claude

The repo ships a SKILL.md. Copy it to ~/.claude/skills/amagi-binder/SKILL.md, point Claude at a folder, and say "make an exhibit binder, Bates prefix DOE." Claude writes the index, runs check, asks you about anything it flagged, then builds the binder. The skill tells Claude never to invent titles or dates.

Limits

  • It numbers and assembles. It does not redact, OCR, or decide what to produce or withhold.
  • Check your court's local rules on exhibit format. The defaults (stamp bottom-right, letter paper, slip sheets) are common, but they aren't universal.
  • Stamps are drawn on top of the page. If a document's content runs to the edge, look at that page and use --box or --position if a stamp covers text.
  • Password-protected PDFs must be unlocked first (for example qpdf --decrypt --password=PASSWORD in.pdf out.pdf).
  • Stamps use the built-in Helvetica font, which covers Western European characters. Other characters in titles or legends print as ?.

If this saved you time

A star helps other people find it. If a PDF stamps in the wrong place, open an issue and attach the page if you can share it.

More AmagiLabs tools

Development

pip install -e ".[dev]"
pytest
python examples/make_examples.py   # rebuild the example exhibits

License

MIT. See LICENSE. amagi-binder uses pikepdf (MPL-2.0), ReportLab (BSD), Pillow (MIT-CMU) and PyYAML (MIT). The example case, its parties and its documents are made up.

Metadata

Release files for amagi-binder 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for amagi-binder 0.1.0
File Size Uploaded Provenance Actions
amagi_binder-0.1.0.tar.gz 93.6 kB Without provenance Details for amagi_binder-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for amagi-binder 0.1.0
File Interpreter ABI Platform Actions
amagi_binder-0.1.0-py3-none-any.whl Python 3 none any Details for amagi_binder-0.1.0-py3-none-any.whl

Total release size: 119.2 kB

Release files / amagi_binder-0.1.0.tar.gz

Download URL amagi_binder-0.1.0.tar.gz
Size 93.6 kB
Tags Source
SHA-256 checksum
How to use checksums
8e9dff15ccd2419a6cd58a5da37fe04e02e032175cd7dd546c78690fc9ae435d
BLAKE2b-256 checksum
How to use checksums
133e214cbae1dfea19f1b8ae5e5e7aec86d60eab109c96aee2b0c5d7d6fb3879
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / amagi_binder-0.1.0-py3-none-any.whl

Download URL amagi_binder-0.1.0-py3-none-any.whl
Size 25.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
526718f360b96905bc473a0b1c7b92c25ae86e9d776eda12199e7c13b6d3ae64
BLAKE2b-256 checksum
How to use checksums
31f1daa35dfdb928d0cfdbae28520e9636abd6ef897bfe88167e15b4a6df56c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Security for amagi-binder 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

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