Agentic Commerce Hackathon 2026
Write one sentence. Agents plan the meals, compare three stores and build the cheapest basket.
One sentence → basketCheapest incl. deliveryMoney moves only on approval sagslay.com
team-09-gwenchanaApplied AI Mongolia × Novelsoft
Problem · Ulaanbaatar households, weekly groceries

“Where is it cheaper?” has no single answer

01

What do we cook?

Tastes, allergies, budget, household size

02

What are we out of?

People rebuy what they already have

03

Where is it cheaper?

3 sites, different packs, different delivery

Real crawled prices

2026-10-05 · same-size items
NominEmart
Eggs, 10 pcs₮6,998₮6,300−10%
Sugar, 1 kg₮7,868₮6,680−15%
Milk, 1 l₮5,398₮5,330−1%
Grand salami₮12,980₮14,300−9%
Cucumber, 100 g₮799₮748−6%
10 / 5of 16 matching items, Emart is cheaper on 10, Nomin on 5
6 / 16different pack sizes: only unit prices compare
₮150kEmart’s free-delivery threshold
What we solved

Six manual chores, now one sentence and two taps

Today
Sagslay
Menu
A daily headache
From the profile: allergies, tastes, diet, budget
At home
Forgotten, bought twice
Pantry stock is taken out of the basket
Prices
Open 3 sites, search every item
Quotes from 3 store agents at once
Pack sizes
Divide 0.9 l vs 1 l by hand
The amount needed, in the cheapest packs
Delivery
Not counted
Every store combination compared, delivery included
Ordering
3 baskets, 3 payments
“Approve” → “Pay”, one transaction
Demo

Sagslay in action

youtube.com/watch?v=xvOUmA96NE0 ↗
Solution

One sentence in Mongolian is enough

I’d like tsuivan tomorrow
Besides tsuivan, should I plan other meals for tomorrow?
Dinner onlyLunch and dinnerAll three meals
drop the salt, we have it
Basket updated. Split across 3 stores, delivery included.
  • ?Clarifies: asks one question when something is missing
  • ≡Plans the menu: tastes, allergies, diet and what is at home
  • ₮Finds the cheapest: real crawled prices plus delivery fees
  • ✎Edits: by chat or by tap, “make day 2 dinner buuz”
Agent workflow

What happens after “I’d like tsuivan tomorrow”

01

Intent

OyuLLM classifies the message and extracts days, dish and headcount. Asks if something is missing

02

Discover

The planner searches recipes over MCP. No carrots in the profile means tsuivan without carrots

03

Decide

Removes what is at home. Asks 3 stores for quotes over A2A and splits for the lowest total with delivery

04 · human

Authorize

“Approve” → “Pay”. Confirmed twice

05

Transact

A sandbox order per store, one MongoDB transaction

06

Verify

Order numbers and the wallet transaction show in the live trace

Data · where real prices come from

Crawled weekly, matched by agents, checked by code

01 · Mon 03:00Crawl

Nomin: 3 catalog categories
Emart: one search per item

~5 minutes
→
02 · crawl_raw5,533 listings

The stores’ public catalogs

→
03 · OyuLLM2 agents match

“Milk 3.2%, 1000ml” → milk, 1 l. Every decision is stored with its reason

→
04 · codeChecks

Is the price and pack size plausible?
52 accepted · 3 to human review · 25 no match

→
05 · MongoDBproducts · prices

Current price + time-series history

Real time?

No. One snapshot a week. Households plan weekly, so this is enough, and it puts no load on store servers.

Coverage

Nomin 19, Emart 33 catalog items have real prices. Good Price is simulated for now and labelled so on screen.

Path to real time

Official store APIs or feeds. Store agents serve quotes over A2A, so swapping the source leaves procurement unchanged.

Research · may we crawl?

We checked each store’s policy and followed it

robots.txtWhat we takeDecision
Nominnomin.mnCatalog open. Only /checkout /account /cart /sign-in disallowedThe public product list its category pages loadcrawl
Emartemartmall.mnNo file (the site returns HTML, API host 404)The site’s own search, one request per catalog itemcrawl
Good Pricegoodprice.mnCatalog open, /api/ /search/ disallowed. AI training crawlers blocked by nameNothing. We found a public product feed updated hourlysimulated

Checked: 2026-10-05

Architecture

How Sagslay works

User

Writes or speaks Mongolian (Anir STT)

↓
React frontend

Chat, live agent trace, basket, profile

REST · SSE →
Agents · FastAPI backend
Orchestrator code, not an LLM

Classifies the message and routes it to the right agent. Does the math and checks itself

UnderstandOyuLLM

Message type and slots (days, people, budget, dish). Code decides what to ask when something is missing

Meal plannergpt-4o · ReAct

Finds recipes and fits the budget

search_recipessearch_productsplan_meals
Procurementoptimizer

Quotes 3 stores at once and finds the cheapest split with delivery

ask_store ×3optimize
Checkoutsandbox

Checks, then one MongoDB transaction

checksensure_accountsplace_order
MCP ↑ plannergrocery-mcp
search_recipessearch_productsbuild_listget_pantryupdate_pantrysave_recipe
A2A ↑ procurementStore agents ×3

Nomin · Emart · Good Price. Agent card, skill quote, JSON-RPC message/send

CrawlersOyuLLM · weekly

2 agents match Nomin and Emart real prices. Good Price simulated

Embedding cachebge-m3

Memory → embed_cache (30-day TTL) → oyu API

↓
MongoDB Atlas

Vector + Atlas Search · time-series prices · transactions · TTL · change stream → live trace

Inside the orchestrator

The LLM classifies, code picks the path

MessagePOST /chat
→
Profiletastes · allergies · budget
→
UnderstandOyuLLM → kind · slots · ask
→
Routercode · if / elif
ask
Clarifying question→waits for the answerwaiting
plan
update_pantryMCP→ Meal plannergpt-4o · ReAct→ List− at home→ ProcurementA2A × 3→ Basketready
edit
remove · add · set · have→re-splitready
plan_change
“make day 2 buuz”→menu and basket updatedready
question · other
basket summary or greeting
ordered
A paid chat is locked, no more edits
run_eventsevery step → change stream → SSE live trace
“Approve” → “Pay”separate path · Checkout · one transaction
MongoDB · indexes and cache

Every query on an index, every vector cached

Atlas Searchproducts
products_vecvectorSearch

bge-m3 · 1024 dims · cosine
filter: store · key · category

+
products_textsearch

name_mn · name_en
fuzzy maxEdits 2: “ондог” → өндөг (eggs)

$rankFusion merges nearest-in-meaning and nearest-in-spelling by rank (RRF k=60, manual below 8.1)
recipes_vecvectorSearch

search_recipes · ingesting tastes from the profile

Plain indexes13 collections
usersphoneunique · partial
pantryuser_id, keyunique
productsstore, keyunique
conversationsuser_id, updated_at ↓
run_eventsrun_id, seqlive trace
orders · wallet_txuser_id, at ↓
pricesmeta.store, meta.key, tstime-series
crawl_matchesrun_id, key

ensure() runs at backend startup and before a crawl writes

TTL · cacheagents/core/embed.py
1
Memory

2048 vectors · repeats within a plan

↓ on miss
2
embed_cache

sha1(model + text) key
TTL index: 30 days

↓ on miss
3
bge-m3 · oyu API

new vectors are written to the cache

The weekly crawl reuses a vector 4 times. sessions also have a 30-day TTL

Technology

Open standards, real data

MCP grocery-mcp

Open MCP server: search_recipes, search_products, build_list, get_pantry. Any MCP client can connect.

A2A Store agents

Every store has an agent card. Procurement asks all three for quotes at once over JSON-RPC.

MongoDB Atlas

Vector + Atlas Search: a typo like “ондог” still finds eggs

Time-series: prices from every crawl

Change stream: live trace

Transactions: all or nothing

TTL: embedding cache, sessions

OyuLLM where it’s strong, gpt-4o where it isn’t

OyuLLM4o-minigpt-4oWe use
Understand9/109/1010/10OyuLLM
Questions4/44/44/4OyuLLM
Crawler3/31/33/3OyuLLM
Recipe5/66/66/6OyuLLM
Plannertimeout✗✓gpt-4o

Strong: Mongolian messages, writing questions, matching Mongolian store listings, where 4o-mini got 1/3

Gap: long multi-step tool use. The planner timed out, so it runs on gpt-4o with OyuLLM as fallback

Few cases, one run per model: a trend, not a verdict · + bge-m3, Anir STT, tsuurAI TTS

Two modes

Order it, or just take the list

Order

The agent completes the purchase

  1. Review and edit the basket
  2. “Approve” → “Pay”
  3. A sandbox order per store (EM-…, GP-…)
  4. Paid from the wallet in one transaction
View only

A list for the store visit

  1. Pick the nearest store or one you choose
  2. The basket becomes a shopping list
  3. Bought items go into the pantry
  4. Money cannot move, blocked in code
Safety

Guardrails live in code, not the prompt

01

Human approval

Money moves only after two steps: “Approve” → “Pay”

02

Pre-order checks

Wallet, budget, allergies, diet, stock, quantities

03

Atomic transaction

If one store fails, everything rolls back. A repeat tap pays once

04

Sandbox

Nothing is sent to real sites, no store passwords are stored

05

Crawl safeguards

A human reviews doubtful matches. robots.txt is respected

06

Audit

Every agent’s thought, tool, result and model is recorded

Business model

We bring stores planned baskets and take a commission

Core revenue

Order commission

Stores pay a commission on every order placed through Sagslay. They gain new online customers who buy a full weekly basket.

Paid by: stores
Add-on

Household Premium

Automatic weekly plans, pantry reminders, price-drop alerts, multiple family profiles.

Paid by: households · monthly
Later

Demand signals

Aggregated, no personal data: what people searched for and didn’t find, at what price households switch stores.

Paid by: stores, suppliers

Principle: ranking is never for sale

The optimizer recommends the cheapest split regardless of commission. Trust is the product.

Next step

A pilot with one store: official API, real orders, agreeing the commission rate.

Try it

sagslay.com

Munkh-Ochiragents · backend
Tuguldurfrontend · backend
Zoljargalbusiness analyst
Demo video: youtu.be/xvOUmA96NE0
sagslay.com QR code
sagslay.com
GitHub repo QR code
GitHub
team-09-gwenchana→ Live demo
← → · F fullscreen · N notes