Inspiration
Across the EU, roughly half of all public contracts attract a single bidder. The usual explanation is corruption. The more common one is arithmetic: a tender dossier runs 40 to 130 pages, the qualification criteria that decide whether a company may legally bid are scattered through it, and a 26-person firm has nobody who can read forty of those a month. So they stop reading, and the field empties out on its own.
The two problems turn out to have the same evidence base. The document that tells a supplier you qualify for this is the same document that reveals this one was written for somebody else -- a specification fixed to 14 mm and 63.5 Wh describes exactly one laptop on the market. Once you are parsing dossiers at scale, both answers fall out of the same pass.
What it does
One button starts an autonomous sweep. No further human input.
The agent pulls open notices, pre-filters by the supplier's value ceiling and live deadlines, then for every surviving notice: opens the dossier, extracts the qualification criteria into structured form, rules each one met / gap / unclear against the supplier's real profile with the evidence attached, screens the buyer's award history and the clause wording for integrity red flags, scores fit out of 100, estimates win probability adjusted for that buyer's historical bidder count, and writes a dated bid plan working backwards from the deadline with an owner on every step.
It ends with a ranked board -- 87 down to 17 across twelve notices -- and a written bid / no-bid brief per notice. The entire reasoning trace streams to the browser while it runs: every tool call with its input, its output and its latency.
The integrity screen
Five detectors, each grounded in a documented single-bidding indicator:
| Flag | Fires when |
|---|---|
| SHORT_WINDOW | The submission window is shorter than the customary minimum, which favours a bidder who prepared before publication |
| THIN_COMPETITION | The buyer averages under two bidders across prior tenders |
| VENDOR_CONCENTRATION | 40% or more of a buyer's prior awards went to one supplier |
| SPEC_LOCK | The specification fixes exact physical parameters instead of performance ranges, which usually describes one product on the market |
| INCUMBENT_LOCK | A qualification clause can only be satisfied by the current supplier |
None is presented as proof of wrongdoing, and the app never says otherwise. Each flag carries the reasoning that makes it worth a clarification question or a formal challenge.
How I built it
TypeScript throughout. Supabase Postgres holds the notices, the supplier profile, the run log and every assessment; Server-Sent Events carry the live trace; the deployed demo runs on Supabase Edge Functions.
The agent core -- orchestrator, six tools, provider adapters, types -- depends on nothing from Node, React or Next. That is deliberate, and it buys a second runtime for free: the same engine drives a Next.js build and a Deno edge build, unmodified.
The decision worth defending is deterministic core, model at the edge. Every score, verdict and flag comes from code that can be read, tested and cited. The language model writes one artefact -- the decision brief -- where prose is the deliverable. This is not a cost saving. A supplier disqualified on a criterion needs to point at the rule that fired; a score that exists only inside a model's context window cannot survive a procurement review board. The side effect is that the hosted demo runs with zero API keys -- open it and press the button.
Graceful degradation at every boundary: no database falls back to the bundled corpus, Supabase unreachable mid-request falls back silently, a deep link to a never-assessed notice is assessed on demand server-side. There is no configuration in which the deployed app shows an error page instead of doing its job.
The board is also published to visiting AI agents over WebMCP -- seven tools registered through document.modelContext -- so an assistant browsing the page can search, screen and re-rank it alongside the human, with every call mirrored on screen.
Enterprise governance and compliance
- Auditability by construction. Every assessment is a row tied to a run, carrying the verdicts, flags, checklist and reasoning mode used. You can reconstruct why the agent said what it said, months later.
- Explainable decisions, not scores. Each verdict ships with its evidence string ("Requires EUR 600,000; profile turnover is EUR 1,850,000"). Each risk flag ships with its rationale.
- Row-level security on all four tables. The demo project's open policies exist because it holds nothing but synthetic notices; a real deployment scopes them to the authenticated supplier.
- No unsourced claims. The integrity screen surfaces the pattern and why the pattern matters -- the standard a challenge before a procurement review body is held to.
- Synthetic corpus. Modelled on the structure of real TED, e-Prokurimi and eNabavke publications. No real notice, buyer decision, supplier name or award record is reproduced.
Monetization
Two customers, one engine.
1. Suppliers -- SaaS subscription (primary). Solo EUR 49/mo: one country, weekly digest, three profiles. Team EUR 199/mo: three countries, daily sweep, unlimited profiles, bid plans exported to calendar. Agency EUR 699/mo: white label, API access, multi-client dashboards for bid-writing consultancies.
The wedge is measurable. A firm bidding six times a year at roughly five days of unpaid bid effort each spends about EUR 12,000 of staff time. TenderLens removes the two days spent deciding whether to bid, and kills the disqualified-on-a-technicality bids entirely.
2. Watchdogs and journalists -- usage-based. Integrity screening billed per thousand notices analysed, with an NGO tier at cost. Anti-corruption organisations and investigative desks already do this by hand, one buyer at a time.
3. Buyers -- compliance licence (later). The same detectors run pre-publication: a procurement office checks its own draft notice for SPEC_LOCK and SHORT_WINDOW before it goes out. Sold per authority, annually. Highest margin, and the one that needs credibility from the first two to earn.
Marginal cost is a few cents of model spend per notice, and zero when the deterministic engine handles it.
Challenges I ran into
Deciding how much judgement to hand to a model. The first version asked an LLM to rule on each criterion; it was fluent and unciteable, and a bid manager cannot take "the model thought so" to a review board. Rewriting the criterion logic as parsed thresholds and set membership made the output defensible and, unexpectedly, made the product better -- the evidence line next to each verdict is what users actually read.
Scoring calibration was worse. The first scorer put eight of twelve notices between 90 and 100, which ranks nothing. Fit is now a five-factor blend -- qualification, capability match, economics against the bid ceiling, historical competition, and slack between the deadline and the work the dossier implies -- and the board spreads properly.
Two bugs only surfaced when I screenshotted the thing: the bid plan was scheduling steps in the past whenever a deadline was closer than its fixed offsets, and a delivery-time commitment was being marked met because the supplier's category matched. Both are fixed. Both were invisible in the happy path.
Accomplishments that I'm proud of
The reasoning trace. An agent that returns a verdict asks to be trusted; an agent that shows six tool calls with their inputs, outputs and latency lets you audit the verdict. Making the trace a first-class contract rather than a debug view is the single decision that most changed how the product feels.
And the zero-configuration demo: it runs, fully, with no key, no database and no signup.
What I learned
That agentic is not a synonym for the model decides everything. The parts of this agent that make it worth deploying -- the tool sequence, the extraction contract, the detectors, the trace -- are engineering. The model is one step in seven, and the system is better for the model being replaceable.
What's next for TenderLens
- A live connector per portal. The portal search is one function; TED first, then the national portals.
- A real dossier reader, with a PDF pipeline feeding the same structured requirement shape, so the agent handles notices nobody has pre-structured.
- Scheduled sweeps with a morning digest. The run loop already has no browser dependency.
- More detectors. Each one is an independent function of the notice, so this is purely additive.
Built With
- ai-agents
- amazon-bedrock
- deno
- gemini
- html
- javascript
- model-context-protocol
- next.js
- openai
- postgresql
- react
- server-sent-events
- supabase
- typescript
- webmcp
Log in or sign up for Devpost to join the conversation.