I want to tell you about Section 3.3.
It’s in the sample employment contract I built to test my PDF Contract Analyzer. It looks like this:
“All inventions, developments, and works of authorship created by Employee, including works created on Employee’s own time and with Employee’s personal equipment, shall be considered works made for hire under 17 U.S.C. § 101 and shall be the exclusive property of Company.”
That clause — buried on page 4, surrounded by unremarkable boilerplate, written in language that sounds like standard legal formatting — means the company owns the side project you’re working on at home. The open-source library you’ve been building on weekends. The app you’ve been quietly developing for two years before you had the nerve to quit.
When I opened that contract and read what the tool had flagged, my reaction was: “That’s excellent.”
Not excellent that the clause exists. Excellent that the tool found it — cited it verbatim, explained exactly why it was dangerous, and tagged it [High] before I’d read a single word of the document myself.
That’s what I built. Here’s how.
The Problem
Contracts are long. They’re deliberately long. The dangerous clauses don’t announce themselves — they live in section 11.4 after twelve pages of definitions, or they’re embedded in a paragraph that starts with something reasonable and ends with a carve-out that changes everything.
Businesses pay lawyers $300 an hour to read contracts carefully. Most individuals don’t have $300. Most employees sign what HR sends them because the alternative is not having a job. Most founders sign SaaS agreements because the alternative is not having the software.
The result: people sign things they haven’t fully read, in language they don’t fully understand, with consequences they discover later.
AI doesn’t fix all of that. But it can tell you which clauses are worth paying the lawyer to look at — before you sign, not after you’re already bound.
What the Tool Does
Upload a PDF. Wait about 20-30 seconds. Get back:
A metadata summary — parties, effective date, governing law, overall risk score from 1-10, color-coded green/amber/red.
Risk flags — severity-bucketed (High / Medium / Low), filterable by category, each one showing the exact clause that triggered it with a section reference and verbatim quote.
Download — the full structured JSON for archiving or piping into other tools.
Here’s what it found in the sample employment contract:
[High] Section 3.3 — IP Assignment: Personal Time and Equipment
"...works created on Employee's own time and with Employee's personal
equipment, shall be considered works made for hire under 17 U.S.C. § 101..."
Non-standard IP grab covering work outside company time. Standard
employment IP clauses cover work done with company resources or
during working hours. This clause extends ownership to personal
projects. California Labor Code 2870 provides some protection but
does not fully override explicit contractual assignment.
[High] Section 7.1 — Non-Compete
"Employee agrees not to engage in any software development activities
for any competing entity within the State of California for a period
of two years following termination..."
Non-competes are generally unenforceable in California under Business
& Professions Code 16600, but this clause creates legal ambiguity and
potential litigation risk if enforced in other jurisdictions.
Not a summary. Not a paraphrase. The exact words, the exact section, the exact reason it’s a problem, and the exact legal context that matters.
How It Works Under the Hood
Four Claude API features doing specific jobs:
PDF support — the document goes in as a native base64 block. No text extraction. No preprocessing pipeline. No lost formatting. Claude reads it the way you would — layout, footnotes, section headers, cross-references intact. This matters when the output needs to say “Section 11.4” and mean it.
Extended thinking — before generating any output, Claude reasons through the ambiguous language. The clause that looks standard but contains a carve-out two sentences later. The liability cap that’s buried in a definition rather than the limitation section. Thinking with a 10,000-token budget fires on every analysis. The thinking itself never surfaces to the user — only the conclusions do — but the quality difference in genuinely ambiguous language is visible.
Structured output — the response is constrained to a strict JSON schema. Every flag must have a severity, a category, an explanation, and a verbatim quote. No flag gets through without a citation. An AI that says “this contract has risky IP language” is interesting. An AI that says “Section 3.3, verbatim: [exact text]” is useful.
Rate-limit handling — a 50-page contract with extended thinking takes 134.9 seconds and consumes most of the Anthropic API’s 30,000 token-per-minute window. The backend has a retry loop with a 65-second backoff. When the rate limit ceiling gets hit, the server retries transparently rather than surfacing a 429 to the user. This is the kind of thing that matters in production and doesn’t appear in demos.
What the Build Session Actually Looked Like
I built this in about 2.5 hours of active Claude Code time, spread across a 5.5-hour session on June 6th.
Here’s what went wrong, because the wrong turns are more useful than the successes:
40 minutes of Node.js that got deleted. The initial scaffold came back as Node/Express. I looked at it and asked one question: “Any particular reason you picked Node and not Python/Django?” The answer was reasonable — a single-language repo with React — and still wrong for my portfolio. Django is my stack. I told Claude Code to fix it and to remember permanently that Python/Django is the default for my backend work. 19 files changed, 857 deletions. Gone before a single line of application logic had been written, which was lucky timing.
The budget_tokens constraint nobody documents prominently. The initial extended thinking configuration used max_tokens=8000 with budget_tokens=10000. The Anthropic API rejected it — budget_tokens must be strictly less than max_tokens. Not a footnote. An actual API error. Fixed to max_tokens=16000.
Rate limit cascade during adversarial testing. The Anthropic rate limit applies when the request arrives, not when it completes. One large document can exhaust the entire token-per-minute window before the next call starts. This produced a cascade of 429 errors across the test suite. Fixed with explicit inter-call delays and retry logic — and documented in TESTING.md so the next developer doesn’t spend 45 minutes figuring it out.
The missing data URI prefix. The browser’s FileReader.readAsDataURL() always prepends data:application/pdf;base64, to the encoded string. The backend had code to strip it. The test suite wasn’t testing that code path because tests sent raw base64. The coverage report caught the gap. One test added. One real production failure was prevented.
The Adversarial Test That Matters Most
Eight edge cases are documented in TESTING.md. The one that matters for trust:
A perfectly fair contract. Clean NDA, standard terms, nothing unusual. Scored 3/10. Zero high-severity flags.
A risk analyzer that hallucinates problems in clean contracts is worse than useless — it trains users to ignore the output. The clean contract test is the one that determines whether the tool is actually usable or just impressive in demos.
It passed.
The Sample Contracts
Five contracts generated by a reproducible ReportLab script — each one designed to look like something you’d actually receive, with the problem clauses embedded in realistic boilerplate rather than labeled for easy spotting:
The NDA has a 10-year term and verbal communication coverage. The SaaS agreement with certified-mail-only cancellation in §11.4. The employment contract with the personal-time IP grab in Section 3.3. The freelance SOW where “satisfactory” means “at Client’s sole discretion.” The commercial lease with joint-and-several personal guarantees from every LLC member.
These aren’t adversarial academic examples. They’re the contracts that actually get signed.
Where It Lives
The code is at github.com/bbornino/claude_pdf_contract_analyizer, and the full project documentation is at bornino.net/projects.
This is Portfolio Project #2 in a series. Each project builds on the last — streaming and caching in Project 1, PDF support and structured output here, prompt engineering and audience modes in Project 3.
The series continues.
#SoftwareEngineering #AI #ClaudeAPI #LegalTech #Python