Inspiration

For a cocoa exporter in Colombia, EUDR compliance is not a checkbox — it is a shipment sitting at port. One missing farm boundary, one ambiguous satellite signal, one land title nobody can find, and the container does not move.

What struck us was the failure mode of the tools built for this. Almost all of them produce a confident green light. But Regulation (EU) 2023/1115 does not ask "what is the risk score?" It asks whether you can prove three things at once (Art. 3): that the commodity is deforestation-free after 31 December 2020 (Art. 2(13)), that it was produced legally in its country of origin, and that a Due Diligence Statement backs it.

Proof is not a number. It is a file a third party can reopen and redo. So we built for the auditor, not for the dashboard.

What it does

EUDR Copilot turns farm plots and satellite screening into an explicit per-plot decision: ready to declare, human review, or blocked.

You draw a plot vertex by vertex over satellite imagery, or import it as GeoJSON or as a GPX track walked with a handheld GPS. Geometry quality control runs immediately: a self-intersecting ring becomes non-conforming data, an overlap between plots blocks the DDS, and a >10% drift between declared and computed area raises a visible warning. The plot enters amber — because drawing a boundary is not evidence.

Forest screening then calls the real Whisp API (Open Foris / Forest Data Partnership). The per-plot verdict maps into the engine and the raw response is preserved with a SHA-256 hash. Legality is captured where it actually lives — with the operator: a per-plot checklist (tenure, land use, labour, FPIC) recorded as dated declarations, each able to carry a supporting document whose SHA-256 fingerprint is stored while the file itself never leaves the operator's machine.

Only when both pillars reach negligible risk does the DDS draft unlock, per plot or per farm, carrying geolocation, product, declaration, and every check with its source, version, date and hash. Every change is an append-only revision of the case file, exportable as JSON toward the five-year record-keeping duty of Art. 4(3).

On top of the deterministic engine, a GPT-5.6 advisor writes the evidence-gap briefing: what is missing per plot, why one went to review, what to do next. It is instructed never to re-score risk or declare legal compliance. The engine decides; the model explains. That boundary is the design, not a limitation.

How we built it

A browser-based modular monolith with zero runtime dependencies. The decision engine is a pure module, deliberately separated from the interface, so one audited ruleset governs GeoJSON validation, risk classification and DDS blocking. Integrations sit behind ports — GeoEvidencePort, StoragePort — so the Whisp adapter and the localStorage case file can be swapped for a real backend without touching the rules.

The engine, UI, synthetic cases, engine tests and base documentation were built in OpenAI Codex sessions with GPT-5.6. The in-product advisor (which calls the GPT-5.6 API at runtime), the real Whisp adapter, the legality checklist with hashed documents, the geometry QA predicates and the persistent case file were wired afterwards with Claude Code. Attribution is documented per file and reflected in the dated commit history.

63 automated tests cover the safety-critical invariants:

  1. Without explicit forest evidence, a plot goes to human review — it is never approved by omission.
  2. An ambiguous signal never becomes a pass.
  3. No DDS is issued if any plot falls short of negligible risk.

Challenges we ran into

Resisting the compliance score. The polished product would have shown a green badge. Satellite evidence is genuinely ambiguous and legality is documentary, so we made human review a first-class outcome and DDS generation a hard gate. The most valuable thing this product does is refuse.

Showing real evidence to a judge with no account. The hosted Whisp API needs a personal key and rejects browser origins by CORS, so our public deployment could show no real forest data at all. Faking a response was never an option — our rule is that a Whisp response is either real or declared absent. So we ran the real screening, archived the verbatim responses with their date and SHA-256, and the app re-verifies that hash on load and labels the evidence archived, not queried live. Archiving is not simulating, and the interface never lets the two blur.

An API that does not echo your identifiers. Whisp returns results without the submitted plot_id, so correlation falls back to submission order. We record the plot IDs at capture time, so reordering plots later can never silently shift evidence from one parcel to another.

Secrets cannot live in a static site. Rather than inject a key into a public build, the app detects that it is running without a server and states on screen exactly what works and what does not — instead of failing with an opaque network error.

What we learned

Regulatory workflows need an audit trail as much as they need an AI interface. The most useful assistant here is not one that decides; it is one that locates the gaps and hands the decision back when the data is uncertain.

We also learned to audit ourselves. Late in the build we found our own documentation citing the five-year retention duty as Art. 33; it is Art. 4(3). We verified every article against the consolidated EUR-Lex text and corrected it. A tool whose entire argument is traceability cannot afford a citation nobody checked.

What's next

Run openforis-whisp on our own Google Earth Engine project, removing the hosted-API dependency. We sized it: 761 calls cover every private rural property in Colombia (3,803,211 plots, DANE census framework) at 5,000 geometries per submission, and the compute lands in the hundreds-to-low-thousands of dollars. The real constraint is not compute — it is that plot-level polygons largely do not exist in public data, which is exactly why field capture matters.

Then: a backend that can honour Art. 4(3) retention, the full Art. 10 legality catalogue parameterised by country, a human-review record (Art. 11), and an export adapter validated against the current TRACES schema with pilot exporters.

Try it: the live demo needs no key — the archived real evidence is one click away. Apache 2.0.

Built With

Share this project:

Updates