Case study · Automated sourcing system

Automating the search for underpriced listings.

I built it for my own resale operation, where the bottleneck is sourcing: in this niche the best listings are gone within minutes. It watches 12 second-hand marketplaces in 9 European countries, classifies what is really for sale, values each listing against observed market references and sends the few worth acting on to my phone.

700K+Listings captured
~5KNew listings a day
12 · 9Marketplaces · countries
4Local AI agents

The system, in production

Metabase · Production dashboard, refreshed every morning
Production dashboard: listings tracked, new listings per day by category, radar alerts by country and category, live listings, sold listings detected and classification coverage.

Captured automatically from the live system every morning; the date is in the bottom-right corner. Figures are system throughput, not trading margins.

In resale markets, an attractive listing only becomes useful when it can be compared quickly with reliable market references, and the best ones are gone within minutes. Doing that by hand across thousands of new listings a day, in several languages, does not scale.

The system handles the repetitive part: collecting listings, classifying them, comparing them with observed references and prioritising the small subset that deserves manual review.

The pipeline runs automatically from collection to classification, valuation, ranking and alerting. The production implementation remains private.

Capture at scale12 marketplaces in 9 countries, at two speeds: catalog cycles every few hours keep the price database complete, and 34 radars re-scan the focus categories every 1 to 30 minutes.
UnderstandingClassifies what is really for sale (a whole PC, a single part, an empty box) and extracts the model and components, with one dictionary per language: 8 so far.
Relative valuationCompares each item with observed market references rather than relying on the seller's asking price alone.
Opportunity rankingScores listings against configurable thresholds so the strongest candidates reach the top of the review queue.
AlertsSends shortlisted opportunities to mobile with the relevant valuation context and target price for manual decision making.

Collection was straightforward. Reliable valuation was harder because marketplace data is noisy, incomplete and often mispriced. The first version produced too many false positives.

The next iterations focused on identifying distorted references, improving data quality and recalibrating the scoring rules. The result was a much smaller review queue, with each candidate supported by market references and a configurable margin threshold.

One rule matters more than any threshold: labels, not filters. A price far below normal is flagged “verify in person”, never hidden. Cheap is not the same as fake, and a filter that removes scams also removes the best deals.

Validation principle

Precision matters more than the number of alerts. A smaller set of well-supported candidates is more useful than a large list of false positives.

The core pipeline stays the same; sources, classification rules and valuation logic change by vertical.

The system separates the reusable pipeline from the rules that are specific to each market. A new marketplace is a configuration file and a language dictionary, not a new program; a new vertical needs its own classification and valuation logic.

01

Reusable pipeline

Collection, deduplication, classification, valuation, scoring and alerting follow the same core workflow across categories.

02

Vertical-specific rules

Each vertical has its own classification and valuation logic, including cases where component value matters more than the whole item.

03

New verticals

The same architecture fits other sourcing problems with structured market references and ranking criteria.

Four local AI agents run on my own server (Qwen 2.5 14B through Ollama), with no data sent to cloud AI services. The rule that took me longest to learn: code detects and calculates; the model translates between people and code. Every time a model was asked to judge, or to produce a figure, false data appeared.

Data agentAnswers business questions in plain language over the whole database (what a part is going for, where it is cheapest, how fast it sells). It never invents figures or links and never writes to the database.
Inventory verifierLists what is in the box of a complete-PC listing: parts present, missing or broken. It never decides whether it is a deal; the code values the parts.
Listing verifierDecides what is actually being sold before a bike deal is reported, instead of guessing from keywords.
Ops agentReports system health and hardware sensors and runs a short list of maintenance actions from a closed catalog, each one only after my confirmation.

The data agent is a cascade ordered by trust. I built the three classic patterns and kept all three; each question stops at the first tier that can answer it:

01

Code first

Valuations, the operations ledger and system status are answered by deterministic code, with no model in the path.

02

Typed tools

The model picks a tool and its arguments; every argument is validated and the query behind it is parametrized and read-only.

03

Verified query catalog

26 hand-written queries the model can select and fill in, including charts and watchlist alerts.

04

Model-written SQL, as a last resort

Only when nothing above can answer: a read-only role, a SELECT-only validator, a forced row limit and a timeout. Every question that lands here is logged, so the catalog grows from real use.

Design principle

The model decides what to ask; the code decides what is allowed to run. Answers are written from the rows that came back, and any link that is not in them is stripped before the message is sent.

View the architecture on GitHub

65+ scheduled jobs and 7 always-on services run on one Windows server. The monitoring is built around one question: did each step produce, not just run?

Monitoring51 checks every 15 minutes that test output: rows still arriving per marketplace, radar passes completed, sold-detection still firing. Each one is tested against old broken logs.
Actionable alertsEvery alert carries the command to diagnose it and how to read the result, resolves itself when the condition clears and is written to an incidents table.
Self-healingHung collectors are killed, a cycle blocked by a site gets one automatic retry, stale locks are cleared and radars brake themselves. After a power cut, the server brings the whole system back with nobody logged in.
Data safetyA run that returns far less than the stored catalog cannot overwrite it. The database is dumped nightly to two physical disks, and a restore is tested automatically every week.
A lesson that cost something

An empty run once overwrote a 142,632-listing catalog, with exit code 0 and clean locks. Since then, every file that accumulates has an anti-wipe guard.

I am not a software engineer by training. I orchestrate the whole system, from the architecture and the product rules to every risk decision and its day-to-day operation, and I program it with AI, specifically Claude, under a protocol I set and enforce:

01

Diagnose first

Measure against the real data before touching anything or adding a rule.

02

Complete, safe changes

Each change is a complete script with a backup, a marker so it cannot apply twice and anchors that abort unless they match exactly once.

03

Verify the real output

I run it on the production server and check what it really printed. Nothing counts as done until the output shows it.

04

Write down the why

Every change ends with a commit that explains why and a changelog row: 500+ commits since July 2026, with wrong hypotheses written down so each mistake is paid for once.

Where the domain rules come from

From me. Some of the most valuable started as me correcting the AI's design: never hide a deal for being cheap, and treat a missing part as a reason to value a listing again, not to discard it.

Back to selected work Contact me