The problem
Public owners mandate their document formats. A DOT, a school district, a municipal authority — the specification prescribes the RFI form, and the contract requires submissions on that form. Procore’s native RFI export is not it.
So the RFI is raised in Procore and then retyped into the owner’s Word or PDF template by hand. The retyped copy becomes the contract record, which means transcription errors land in the contract file, and the effort repeats for every RFI on every job.
The approach
Don’t rebuild the owner’s form. Fill it.
The owner’s blank PDF is kept as the background and values are stamped onto it. Fidelity is exact by construction — the printed layout is theirs, so it cannot drift.
The obvious alternative is to reconstruct each form as a Word template. That was tried first, and it is where fidelity quietly dies: column widths shift, rules collapse, and no validation can detect it, because a template that renders wrongly is still a structurally valid document. Stamping removes that entire failure mode.
How it works
- Upload the owner’s blank form. Any PDF. It is validated as static — scripts, embedded files and auto-run actions are rejected.
- The app reads its geometry. Captions, rules and boxes are extracted and matched to RFI fields against a fixed catalogue. Deterministic, no language model: the same form always maps the same way.
- A person confirms the placement. Proposed fields are drawn over the rendered form and can be dragged onto the right blank. Anything the matcher is unsure of prints nothing until it is confirmed — a blank field is recoverable, a confidently wrong one on a contract document is not.
- Generate from any RFI in the project, from the side panel, in a couple of clicks.
Inside Procore
Side panel
Opens alongside the RFI tool. Pick an RFI, pick a form, generate.
Full-screen tool
Upload owner forms, place fields visually, manage them per project.
Signed in as you
Three-legged OAuth, so it sees exactly what the logged-in user sees.
Per project
App configurations carry each project’s number, contract and forms.
What the platform taught me
Several of these are not in the documentation. Each was settled by instrumenting the app and reading what Procore actually sent, rather than assuming.
Not in the URL, not over postMessage. The official iframe
helper is an authentication helper only. The project has to reach the app
another way.
{{double}} braces.
{single} passes through as literal text. There are no
built-in context tokens.
Which turns out to be the mechanism that makes multi-project work possible — each project’s configuration carries its own values.
Permissions still read as correct; the account is simply no longer in the
project directory. It presents as a 403 with a valid token, and
list_projects returning zero is the tell.
Persist the rotated one or the next request replays a spent token and the session dies minutes after sign-in.
How it is built
Python and FastAPI on Cloud Run. pdfplumber reads form
geometry; PyMuPDF stamps the values. No Office runtime is
involved, which keeps the image near 200 MB and removes a whole class of
rendering drift.
Credentials live in Secret Manager, sessions are encrypted cookies because the service scales to zero across instances, and uploaded forms are stored partitioned by company and project so no tenant can see another’s. The same modules back a command-line tool and the web app; roughly 170 tests and a clean type check.
The matcher has been exercised against real owner forms — the Toronto Transit Commission, New York State DOT, USACE (ENG 6108), NAVFAC and the National Park Service — each of which broke it in a different way before it handled them.
What it does not do yet
- Runs in a Procore sandbox; it has not been installed in production.
- Automatic matching resolves roughly two thirds of captions on a dense form. The rest are one click each in the editor — deliberately, since guessing is worse than asking.
- Scanned, image-only forms produce no fields. That case needs OCR, which has not been added.
- The panel session depends on third-party cookies being allowed in the browser.
- Generated documents are downloaded, not attached back to the RFI. Writing to Procore would mean giving up the read-only guarantee, which is a deliberate decision rather than an oversight.