DEV Community

Josiah Wilson
Josiah Wilson

Posted on

I built a local-first contract obligation extractor with open-weight models — because contracts shouldn't have to leave the building

Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle Submission 💸

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle

What I built

Obligation Register, local edition: a small Python tool that reads a
short business agreement and extracts every obligation — who owes what,
how much, by when — each one pinned to a verbatim source quote from
the document. No cloud API. No per-document fee. The document never
leaves the machine it runs on.

This is the extraction engine for a service I sell manually today: a
fixed-price Contract Obligation Register ($150, one agreement up to 10
pages, delivered with source quotations and unclear items flagged, no
legal advice). The manual version works — but it doesn't scale, and
sending a client's supplier agreement to a third-party API is exactly
the kind of thing my customers are nervous about. A local open-weight
model removes both problems at once.

How it works

  • Ollama serves the model locally; the extractor is ~150 lines of Python standard library — no dependencies to install.
  • The model is instructed to return only a JSON array of obligation packets: obligated party, obligation, amount, deadline, and a verbatim source quote.
  • Every extraction is scored against a human-authored ground truth, and a quote only counts if it appears in the document — the model proposes, the evidence decides.

The demo (fictional document, real numbers)

I wrote a fictional services agreement (Juniper Table LLC + Cove Supply
Co. — invented parties, zero client data) with 6 planted obligations:
a $2,500 payment at net 30, a $1,000,000 insurance requirement, a
cycle-count deadline, a $500 variance-reconciliation duty, a
confidentiality prohibition, and a 14-day termination right.

Results on this machine (2 CPU cores, no GPU):

Model Captured Time Notes
Qwen 2.5 0.5B 5 / 6 ~29 s Missed the confidentiality prohibition
Qwen 3 4B 6 / 6 ~4 min Complete, including the prohibition
Gemma 3 1B not run — Attempted: this sandbox's resolver maps the model registry's CDN to a synthetic non-public address, and the pull is refused. Reported, not hidden.

The 0.5B miss is the most interesting result in the table: small models
skip prohibitions — duties phrased as "shall not." That's precisely
why the product wraps the model in a human-review gate instead of
pretending extraction is the deliverable. The register flags what it's
unsure about; a person verifies. Automation proposes, evidence decides,
humans approve.

Why open matters here

  • Privacy: a contract processed on a $0 local model never transits anyone's cloud. For legal-adjacent documents, that's not a feature — it's the whole sale.
  • Cost: per-document API pricing makes a $150 flat-fee product marginal at volume. Local inference makes the marginal cost of one more document zero.
  • Auditability: open weights + a pinned model version mean the extraction is reproducible — a client (or a court of their own skepticism) can re-run the exact same pipeline.

What's next

  • PDF ingestion and page-level quote anchoring.
  • The human-review queue as a tiny local web UI (approve / correct / reject per obligation).
  • A paid pilot: first real register delivered with the local pipeline, human-verified, at the same $150 flat fee.

Links

Built for the DEV Hacktoberfest Open-Source AI Challenge, Week 2 —
Side Hustle.

Top comments (0)