The afternoon an RFP drops
Someone on the proposal team opens a long PDF and starts a spreadsheet by hand: every item the agency will score, its points, what it asks for, what the scorer will look for.
Then they hunt through the fine print for the rules that throw a proposal out before anyone scores it. Turned in late. A required form missing. One page over the limit.
Two small slips cost the most. A criterion paraphrased in the spreadsheet stops matching the words the scorer is holding. A disqualifier nobody copied over sinks the bid, no matter how good the rest of it is.
What you get back
One page per RFP, in the RFP's own words. The headings and labels are ours; every quote is theirs.
How you'll be scored
Every item the RFP scores, its points, what it asks you to provide, and what the scorer looks for, grouped under the RFP's own headings. The points are added up and checked against the total the RFP states.
What gets you thrown out
Every sentence that rejects or disqualifies a proposal, sorted by kind: late, missing something required, broke a page limit. This is the part that fails silently when it's built by hand, because nobody notices a line that isn't there.
Every line links to its source
Click a chip like Page 14, line 15 to open that RFP page with the words highlighted. Where the RFP says nothing, the cell reads not in source instead of a guess.
How it's kept honest
A checker re-reads every quote against the RFP and refuses the output if one word isn't at its citation, or if any scoring or disqualifying line was left out. The page is only built from a checklist the checker passed.
The shipped checklist passes:
$ python3 tools/check_matrix.py outputs/tucker-ga-rfp-2026-008-row-maintenance.matrix.json PASS 3 rows, every cited claim found in the source; points 100 vs stated 100 (reconciles); coverage 30 trigger line(s) accounted for
Change one word, considered to reviewed, and it refuses:
FAIL 1 problem(s)
- disqualifiers 1: text is not verbatim (whole words) at p3:23-p3:24: 'Late bids will not be reviewed.'
Real output from the repo's checker, trimmed to fit. The tests prove it also refuses a respelled word, a figure borrowed from the next line, a wrong page, and a disqualifier nobody accounted for.
How to use it
In Claude Code
Open the folder, put the RFP PDF in it, and say:
Translate rfp.pdf.
Claude extracts the text, writes the checklist, runs the checker, and renders it. The rules it follows are in identity.md and rules.md.
From the command line
Python 3.9+ and poppler for PDFs. Full steps are in the README.
Turn the PDF into numbered source text.
python3 tools/extract.py fixtures/your-rfp.pdfAsk Claude to translate the source text into a checklist.
Check it against the RFP.
python3 tools/check_matrix.py outputs/your-rfp.matrix.jsonRender it as Markdown, CSV, Excel and HTML.
python3 tools/write_matrix.py outputs/your-rfp.matrix.json
More demos
Three public RFPs, each turned into a checklist and passed by the checker.
- City of Tucker, GA
RFP 2026-008Right-of-Way Maintenance Services100 points across three criteria, and 12 rules that can throw a proposal out - City of Tucker, GA
RFP 2026-016Construction, Engineering and Inspection (CEI) Services100 points across three criteria - Colorado Department of TransportationUS 50 Passing Lanes, Construction Manager servicesA 60-point proposal and a 40-point interview, with sub-criteria

