▶ Live demo: office-action.kareemghazal.com
Paste an independent patent claim, a specification support excerpt, a prior-art reference, and a synthetic §102 office action (or "Load sample") and get a gated response draft: a deterministic parse of what the examiner actually charted, an argument targeting only the un-charted limitations, a proposed amendment — and a deterministic no-new-matter gate that fails loudly, listing the exact unsupported words, if the amendment reaches beyond the specification. (First run ~15–30s.)
Educational tool — not legal advice. It drafts a first-pass response to a synthetic single-reference §102 anticipation rejection; it does not handle §103 obviousness, real office-action formats, or filing requirements, and it makes no promise about any legal outcome. Use synthetic or public patent text only. Consult a qualified patent attorney for anything that matters.
An examiner's §102 rejection is only as good as its charting: every limitation must be met by
what the reference actually says. And an applicant's amendment is only as good as its
written-description support: no new matter. office-action makes both checks deterministic:
claim ─────────────► segment_claim (deterministic) ───► limitations
office action ─────► parse_rejection (deterministic) ─► CHARTED / UN-CHARTED per limitation
│ charted only if the examiner quoted reference text
│ AND the quote is a verbatim substring of the reference
▼
un-charted limitations = the argument targets
▼
reference + spec support ──► LLM draft (structured output)
argument points + proposed amendment
▼
DETERMINISTIC GATES (pure functions — no LLM, no wall-clock)
• no-new-matter: every content word the amendment adds must appear
verbatim in the SPEC SUPPORT (violating words listed)
• quote grounding: every quoted passage in the argument is verbatim
from the reference or the claim
• argues-only-uncharted: "not disclosed" only where the parser agreed
• amendment required when everything was properly charted
▼
response draft + gate report (PASS / FAIL + exact violations)
- The claim is split into limitations deterministically (semicolons / newlines / "wherein" / ", and" — deliberately not bare "and"; same approach as the companion claim-chart tool).
- The office action is parsed deterministically: a limitation counts as charted only if the rejection quotes reference text for it and that quote really is a verbatim substring of the reference (whitespace/case/curly-quote-normalised). A paraphrased or invented "quote" proves nothing — un-charted limitations become the argument targets.
- The LLM drafts (structured output): one argument point per un-charted limitation and a proposed amendment to claim 1. If everything was charted, the draft concedes and rests on an amendment drawn from the spec support.
- Deterministic gates verify the draft — the killer feature is the no-new-matter gate: every content word of the amendment (beyond stopwords and words already in the original claim) must appear verbatim in the specification support, or the gate fails and lists the violating words. The model drafts; it never gets to self-certify.
Built around one idea — measure, don't vibe: the parser and every gate are pure functions with a planted-case eval set (expected charted/un-charted labels, a planted trap amendment with its expected violation words), so correctness is measured, not asserted.
Requirements: Python ≥3.10 (backend) · Node ≥18 (the web/ UI). The offline tests and the
deterministic evals need no API key.
python -m venv .venv && source .venv/bin/activate
pip install -e .
cp .env.example .env # add ANTHROPIC_API_KEY (only needed for drafting, not for parsing/evals)
office-action demo --parse-only # deterministic rejection parse — no API key needed
office-action demo # full pipeline on the Amazon 1-Click sample
office-action demo --case new-matter-trap
office-action parse --claim-file claim.txt --reference-file ref.txt --office-action-file oa.txt
office-action respond --claim-file claim.txt --spec-file spec.txt \
--reference-file ref.txt --office-action-file oa.txtSample output (office-action demo --parse-only) — the deterministic rejection chart:
╭──────────────── Rejection chart (deterministic) ────────────────╮
│ 3/6 limitations properly charted by the office action │
│ 3 un-charted limitation(s) = the argument targets. │
╰──────────────────────────────────────────────────────────────────╯
# Limitation Charted Examiner's quote (verified?)
1 under control of a client ✓ charted "the browser displays information
system, displaying information … identifying the item …" verbatim ✓
2 in response to only a single ✗ un-charted "the shopper completes the purchase
action being performed, … with one quick click …" NOT in reference ✗
3 under control of a single-action ✗ un-charted — The office action does not address
ordering component … this limitation.
…
The full pipeline then drafts the argument + amendment and prints the gate report
(✓ PASS no_new_matter, ✗ FAIL … with the violating words).
Three bundled cases (office-action demo --case <name>, also served at /api/samples):
real-patent-us5960411-oneclick— the claim of a REAL granted (and expired) patent: claim 1 of US 5,960,411 (Amazon "1-Click", 1999), with a synthetic shopping-cart reference and a synthetic hand-waving rejection. The examiner charts the generic steps with verbatim quotes, offers "quotes" for the single-action limitations that appear nowhere in the reference, and never addresses the single-action ordering component at all — the parser must find limitations 2, 3 and 6 un-charted, and the argument must target exactly those.all-charted-thermostat— a properly-charted rejection: every quote verifies verbatim, so there is nothing to argue; the draft must concede the charting and rest on an amendment pulling the hysteresis feature from the spec support (no-new-matter gate passes).new-matter-trap— the spec support deliberately lacks the tempting distinguishing feature (it describes only a passive liquid-crystal strip). A lazy "smart mug" amendment (wireless transmission to a phone app) imports new matter, and the gate must catch it — tested deterministically with a planted bad amendment, not by hoping the live model fails.
python evals/run_evals.py # deterministic gates — parser + no-new-matter + grounding
# (NO API key needed: the parser and gates are pure)
python evals/run_evals.py --judge # also draft live responses and run the opus judge- Parser — per case, the charted / un-charted limitation indices match the labels in
evals/dataset/cases.jsonexactly; the labels are cross-checked against the segmented limitations, so a mislabelled dataset fails loudly instead of silently passing. - No-new-matter — the planted supported amendment passes; the planted trap amendment fails listing exactly the expected unsupported words.
- Quote grounding — the planted verbatim-quoting argument passes; the planted fabricated quote is caught.
- Judge (
--judge) — the live drafts must pass every deterministic gate, and opus scores them: professional register, sound distinctions, targets exactly the un-charted limitations, and no legal-outcome promises.
Every run writes a reproducible artifact to
evals/results/latest.json — per-case outcomes, the models used,
and a timestamp. Any number quoted about this tool should come from that file.
Latest run (claude-sonnet-4-6 drafter, claude-opus-4-8 judge — full results in
evals/results/latest.json): all gates pass — parser correct on
3/3 labelled cases (the real 1-Click claim parses to charted {1, 4, 5} / un-charted
{2, 3, 6} — exactly the single-action limitations), 4/4 planted no-new-matter checks and
2/2 planted quote-grounding checks behave as labelled, every LIVE draft passes all four
deterministic gates, and the opus judge scores all three drafts 5/5 (professional, sound,
targets the right limitations, no outcome promises).
The gates and the judge both earned their keep on live drafts:
- The quote-grounding gate originally rejected legitimate prosecution-style quoting — bracketed case alterations ("[t]he outer surface…"), trailing punctuation, ellipsis-split quotes, and quotes drawn from the specification or the office action itself. The gate now normalises those conventions and accepts any document in the record as a quote source — while a quote from nowhere still fails.
- The no-new-matter gate originally flagged inflections: an amendment saying "changing" against a spec that says "changes" is the same disclosed concept, not new matter. Words now meet on shared stems — while genuinely unsupported words (the planted trap's "mobile", "paired", "wirelessly") still fail with the exact violating words listed.
- The judge caught a live draft promising a legal outcome; the drafting prompt now bans the phrasings outright ("overcomes the rejection", "condition for allowance", …).
It's a small, hand-labelled set — enough to gate the parser + gate logic, not a benchmark; add
your own — each case is one JSON object in evals/dataset/cases.json:
{ "name": "my-case",
"claim": "A device comprising: A; B; and C.",
"spec_support": "...application text that supports amendments...",
"reference": "...prior-art text...",
"office_action": "...synthetic rejection quoting the reference...",
"expected_charted": [1, 2],
"expected_uncharted": [3],
"planted_amendment_fail": "...claim with unsupported words...",
"expected_new_matter_words": ["wirelessly"] }- Single-reference §102 anticipation rejections only, and synthetic office actions — the parser expects examiner language that restates each limitation and quotes the reference; it does not read real USPTO office-action PDFs, §103 combinations, §101/§112 rejections, or restriction requirements.
- Charted = verbatim-quoted, nothing more. The parser verifies that the examiner's quote exists in the reference — it does not judge whether the quote substantively meets the limitation (that responsiveness judgment stays with the human; a verbatim quote can still miss a qualifier). The converse is the safe direction: an unverifiable quote never counts.
- No-new-matter is a word-level verbatim check — deliberately strict and literal (inflections count as violations: spec "selects" does not support amendment "selection"). It is a tripwire for unsupported matter, not a legal §132 analysis.
- The
argues_only_unchartedgate checks the structured argument points; free-running prose in the conclusion is constrained by prompt, not by the gate. - Best on synthetic or public patent text; treat every draft as a first pass for a human practitioner to rewrite — not something to file. Not legal advice.
pytest -q # offline: segmentation, deterministic rejection parsing (verbatim → charted,
# paraphrased → not charted), the no-new-matter gate (violating words listed),
# quote grounding, the planted new-matter trap, sample integrity
# (fake client, no API key, no network)web/ — a Next.js UI: four textareas (claim, spec support, reference, office action), the
charted/un-charted rejection table (with the examiner's quote and whether it verified), the
argument draft, the amendment draft with a no-new-matter PASS/FAIL badge (violating words
listed on failure), and the not-legal-advice banner throughout.
Run it locally in two terminals:
# terminal 1 — the API
pip install -e .
cp .env.example .env # add ANTHROPIC_API_KEY
python -m uvicorn office_action.api:app --port 8000
# terminal 2 — the UI
cd web
npm install
echo "NEXT_PUBLIC_API_URL=http://localhost:8000" > .env.local
npm run dev # open http://localhost:3000See DEPLOY.md — the FastAPI backend on Railway (via the Dockerfile; needs
ANTHROPIC_API_KEY) + the Next.js web/ UI on Vercel, ~5 minutes.
MIT — see LICENSE.