-
-
Sign-in page of the ChainGuard AI dashboard, with English and Turkish interface.
-
Desktop alert from the pipeline: Nemotron flagged a tariff increase on Chinese-origin computer parts.
-
The same alert in Slack on a phone: a 0% → 20% duty increase affecting Cooler Master, ASUS and Gigabyte.
-
Suppliers list filtered by “Reorder needed” and sorted by risk score.
-
Notification settings: each user chooses channels and which severity levels to receive.
-
The same risk map as a table: every supplier’s route, annual purchases and risk score.
-
Stock coverage per part compared with the days needed to reorder (transit + customs + safety margin).
-
Dashboard overview: high-risk suppliers, active events, annual extra cost and parts to reorder at a glance.
-
In-app notifications: the dashboard warns when a part’s stock falls below its reorder level.
-
Excel import: company data is loaded into the database in one step, and existing records are never overwritten.
-
Risk map of supplier routes to Türkiye: hover a port to see the supplier, risk score and annual purchases.
-
All 9 suppliers with risk score, origin, transport time, annual purchases and stock status.
Inspiration
A manufacturer that imports parts usually learns about a new duty, a port closure or a price jump when the invoice arrives. By then the cost is already locked in. The signals were in the news days or weeks earlier, but they were spread across many countries and languages: a customs decree in Turkish, a typhoon warning in Chinese, a memory price forecast in Korean.
We wanted an agent that reads that news for the company, knows its suppliers, and answers three questions on every scan: Does this affect us? Which suppliers? How much will it cost?
To test the idea we created KurguTek, a fictional desktop PC maker in Ankara that builds 10,000 PCs a year with nine suppliers in China, Taiwan, Vietnam and South Korea. Each supplier has its parts, HS codes, routes, ports, contracts and trade agreements in the database.
What it does
ChainGuard AI is a scheduled pipeline with five stages:
Scan: Tavily searches official, state-agency and trade-press sites for new customs duties and taxes, trade restrictions, port and airport disruptions and component price changes. The search queries are generated from the supplier data, and rule-based filters remove noise before any model sees it. Agent: NVIDIA Nemotron 3 Super on Nebius Token Factory screens each article against the supplier list. Nemotron 3 Ultra analyses only the relevant ones: it checks the suppliers Super proposed, adds any it missed, and extracts the facts the cost model needs (event type, tax type and old and new rates, effective date, delay in days, price change). It writes an English summary with a supporting quote in the original language. Cost and alerts: the cost impact is calculated for each supplier part with Turkish import taxes (customs duty GV, additional customs duty İGV, Kültür Fonu, ÖTV) together with stock coverage. The results are grouped into alerts that are tracked across scans as new, changed, unchanged or resolved. Panel: new, changed and resolved alerts are pushed to the ChainGuard web dashboard through a token-protected API. Notify: important alerts are sent to Slack, Teams, e-mail and other channels.
The scan interval is set from the panel (1, 3, 6, 12 or 24 hours). Admins can also import company data (suppliers, parts, contracts, shipments, stock) from an Excel file.
How we built it Models: Nemotron 3 Super and Nemotron 3 Ultra through Nebius Token Factory (OpenAI-compatible API). Both stages return JSON that is validated with Pydantic schemas. Search: Python with the Tavily API, a domain whitelist, relevance rules and a query planner that turns the supplier list into search queries. Data: PostgreSQL 17 in Docker. The database connects the stages: each stage reads its own pending work from Postgres, so a failed stage is picked up on the next run and re-running a scan changes nothing. Panel: Nuxt 4, with unit tests (Vitest) and end-to-end tests (Playwright + pytest). Notifications: Apprise, so one setting covers Slack, Teams, e-mail and desktop notifications. Scheduling: an hourly Windows Task Scheduler job that runs a scan only when the interval chosen in the panel has passed.
Cheap filter, expensive analyst. We ran Nemotron Nano, Lightning, Super and Ultra on the same test set. Super caught every relevant article at about a third of Ultra's price per token, so it screens everything, one article per call. Ultra matched suppliers and extracted numbers most accurately, so it only reads what Super lets through. Ultra also acts as a verifier for Super's supplier list, and this fixed both missed and extra suppliers.
Impact score. The model never invents a number. It reports the status of the event, and the code turns that into a score. The status picks a band $[L, H]$:
Status Band In force or ongoing 80–100 Proposed 66–79 Unclear or forecast 61–65 Not relevant 10
The size of the event then moves the score inside the band:
$$\text{score} = L + \operatorname{round}!\left(\frac{p}{20}\,(H - L)\right), \qquad p = p_{\text{suppliers}} + p_{\text{event}}, \quad 0 \le p \le 20$$
where $p_{\text{suppliers}} = \min(2n, 10)$ for $n$ affected suppliers, and $p_{\text{event}}$ (at most 10) depends on the event type:
a duty increase gives $(r_{\text{new}} - r_{\text{old}})/2$ points; a delay of $d$ days gives $10 \cdot \min(d, 14)/14$ points; a price increase of $x\%$ gives $x/4$ points.
Good news, such as a duty cut, scores 0 size points. This way a 20-point duty increase on five suppliers ranks above a 2-point increase on one, and the same facts always give the same score.
Challenges we ran into Batching. To save cost we sent Super six articles per call. It once left an article out of its answer, so we switched to one article per call. Translating qualifiers. Turkish "en az" (at least) was translated as "up to", and later "at least" was added where the text had none. A wrong qualifier changes the cost, so we added an explicit rule to translate qualifiers literally. Same city, different point. A typhoon at Kaohsiung airport was matched to a supplier shipping from Kaohsiung seaport. The fix was a rule that the problem must be at the same kind of point the supplier uses. World knowledge over our data. After we removed the Suez Canal from our route data, both models still flagged a Suez diversion, reasoning that ships from China to Turkey pass through Suez. That is true in the real world but wrong for our data. We now tell the model that only the departure and arrival points in the list count. Invented dates. For an article with no effective date, Ultra once used the publication date. Now the field stays empty unless the text states a date. Run-to-run consistency. Some borderline cases, such as a new mandatory certificate or an analyst price forecast, were classified differently between runs. The cause was an unclear definition, not a wrong answer, so we rewrote the definitions until each case had exactly one correct category. Fitting four parts together. Search, agent, cost and panel were built by four people in parallel, so the database schema became our contract. We had to agree on details such as which rows an article creates, so that the cost module could apply free trade agreement rules correctly, and make every stage safe to re-run. Accomplishments that we're proud of 27 out of 27 correct on a test set of 27 articles in 8 languages (Turkish, English, Chinese, Vietnamese, Korean, Japanese, Thai, Malay), 11 of them deliberate traps: wrong product, wrong port, same city but different point, rumours, good news. A few cents per run. A full agent run over 38 articles cost $0.23 (about $0.006 per article). A run with no new articles costs nothing. A complete pipeline, end to end. From a news search to a cost figure on the panel and a message in Slack, with no manual step in between. Safe to re-run. Only the scan can fail a run. Every other stage catches its own errors and picks up missed work on the next run, and re-running a scan changes nothing. What we learned A two-model setup in which one model checks the other worked better than one larger prompt. Rules before the LLM. Generating queries from the supplier data and searching only trusted domains gave the model less noise and made results reproducible. Most of the work was consistency, not accuracy. Clear definitions and explicit rules mattered more than model size. Let the model extract facts and let code do the math. Scores and costs computed in code are reproducible and explainable. Build a test set with traps early. Every rule we added came from a trap the model fell into. Keep secrets out of code and archives from day one. In a team of four, an API key easily ends up in a shared zip. What's next for ChainGuard AI From one company to many. ChainGuard AI runs today for one company on a single Windows machine. Next, we want to move it to a cloud server so that any manufacturer can sign up, load its own suppliers and get alerts for its own supply chain. More suppliers, countries, sources and languages. Our example company has nine suppliers in four countries, and the agent already reads news in eight languages. We want to cover more supplier countries, add more official and trade-press sources for each of them, and test the agent on more languages, so it can follow a real manufacturer's full supply chain.
Built With
- apprise
- docker
- microsoft-teams
- nebius-token-factory
- nemotron-3-super
- nemotron-3-ultra
- nuxt
- nvidia-nemotron
- openai-api
- playwright
- postgresql
- pydantic
- pytest
- python
- qdrant
- slack
- tavily
- typescript
- vitest
- vue
- windows-task-scheduler
Log in or sign up for Devpost to join the conversation.