The most expensive contract mistake isn't a bad clause. It's a missed date.
Auto-renewal kicks in because no one set a calendar reminder 60 days out. A termination notice arrives late because the notice period was buried in Section 14(b). A payment default triggers because the cure window expired while the email sat in a folder.
This is a solved problem, if you actually extract every date from the contract when you first read it. Most lawyers don't, because doing it manually takes long enough that it gets deferred. I built a two-step pipeline that does it automatically and returns a ranked list of deadlines the moment you paste the contract in.
Here's the full pipeline.
The pipeline
Two GPT-4o calls. First pass extracts everything date-related from the contract in plain language. Second pass structures it into a sorted JSON list with a risk level on each entry.
Step 1 reads the contract and surfaces every time-based obligation: exact dates, relative deadlines ("30 days after signing"), notice periods, auto-renewal triggers, cure periods, payment schedules, and anything else tied to a clock.
Step 2 takes that extraction and maps it to a consistent schema: label, absolute date if determinable, relative expression if not, a risk tier, and the exact clause it came from. It sorts by risk so the dangerous ones are at the top.
The risk tiers are the key design decision:
- High — auto-renewal opt-out windows, termination/cancellation notice periods, cure periods, response deadlines. Missing these causes something automatic and bad.
- Medium — payment due dates, milestone deadlines, expiration dates. Important but usually visible.
- Low — effective date, execution date, commencement. Informational.
Step 1: Extract date references
The extraction prompt is deliberately open-ended. You want it to surface everything, including relative timelines that have no absolute date yet, rather than only picking up dates that look like calendar entries.
The key line is the list of what to include. Without it, the model catches explicit dates but misses things like "upon 30 days written notice" or "annually on the anniversary of the effective date," which are exactly the ones that get missed in real practice.
Step 2: Structure to JSON
The structure prompt maps the extracted text into a single JSON object with a dates array — one entry per deadline or date reference found in the contract. A standard services agreement might come back with 6–12 entries; a lease with quarterly payments and a 60-day renewal window might return 15+.
The risk classification rules matter here. "High" is specifically defined as anything where missing the date causes an automatic consequence — commitment, default, loss of rights. That keeps the model from flagging the effective date as high-risk just because it sounds important.
The clause field (capped at 200 chars) is what makes the output useful in practice. Instead of just "Auto-renewal opt-out: 60 days before anniversary," you get the exact sentence from the contract so you can verify it without going back to search.
Try it on your own contract
Paste any contract — NDA, services agreement, lease, employment offer — or upload a PDF or DOCX. The pipeline runs two API calls and returns a sorted list with risk levels and source clauses.
Works on any contract type. Not just PI — leases, vendor agreements, NDAs, employment contracts, licensing deals.
What to do with the output
The extracted list is a starting point, not a finished calendar. Once you have it:
- Verify the high-risk entries first. Find the exact clause in the original contract and confirm the date or triggering event is correctly interpreted.
- Add absolute dates to relative deadlines. If the contract says "30 days before the anniversary of the effective date" and you know the effective date, calculate the actual calendar date.
- Put every high and medium entry into your calendar system with a lead time appropriate to the notice period.
- Flag anything in "missing or unclear" — usually an undefined execution date or an ambiguous renewal trigger that needs attorney interpretation.
The pipeline catches everything. The attorney decides what to do with it.
How it handles edge cases
A few things worth knowing:
Relative deadlines with no anchor date. If the contract says "30 days after execution" but doesn't include the execution date, the pipeline returns date: null and relative: "30 days after execution" and flags it in missing_info. You still see the obligation; you just need to supply the anchor.
Multiple payment dates. The pipeline treats each payment milestone as a separate entry. A contract with quarterly payments returns four medium-risk entries, each with its own clause reference.
Auto-renewal buried in definitions. These get caught because Step 1 explicitly looks for them, not just for dates that look like calendar entries. The extraction pass reads for obligation patterns, not just date formats.
Long contracts. The tool handles up to 50k characters — roughly 35 pages — which covers most standard commercial agreements. If you're analyzing a 200-page master services agreement, split it by section.
Copy the full pipeline
Both prompts are copyable above. The only change you need to make the pipeline work in your own setup: replace {contract_text} in Step 1 with your contract content, and replace {extracted_info} in Step 2 with the output from Step 1.
If you want to build this into a script or app, the full implementation is the same pattern as the intake pipeline and demand letter generator — a server-side route with two chained API calls and deterministic post-processing. Nothing clever, just reliable.