Team Moonshot · submission brief
An open MCP and REST front door that lets a customer's own AI purchasing agent buy from Valio Aimo at a signed fixed price, inside limits a person signed, with a log anyone can verify.
npm run evidence.simulated: true.| Criterion (weight) | What we built | How to check |
|---|---|---|
| Working end-to-end demo (30%) | Buyer side (/buyer): the agent takes "1,000 litres of lactose-free milk by Monday", gets a signed offer, and the order confirms; 1,600 litres waits for the approver. | /buyer?tour=1; npm run eval -- --suite scenarios |
| Solving the problem and user need (20%) | Search reads Finnish, Swedish or English needs as a product concept plus claims (for example lactose_free) and returns a match confidence. | eval 2; eval 12 |
| Autonomy and controls (20%) | 18 named mandate rules run on every order; each result (pass, ask or block) is listed on the order with its reason. | npm run eval -- --suite guardrails; eval G10 |
| Robustness to exception situations (15%) | Short stock: a split (keep what is in stock, fill the rest like for like) or a full substitute, each signed and each checked against the buyer's words for what it delivers. | eval 5; eval 6 |
| Openness and credible path toward production (15%) | 11 MCP tools and 41 REST operations on 35 paths, from one schema set. | npm run eval -- --suite openness; /api/v1/openapi.json |
Valio Aimo's customers, kitchens of hotels, schools and restaurants, will soon send their own AI agents to buy. The challenge asks for a way to let those agents order from the wholesaler that both sides can trust: Valio Aimo must know the agent acts inside what its customer allowed, and the customer must know the agent buys the right thing at the agreed price. It must work in the exception cases (short stock, late delivery, a new product), keep a person in charge of the decisions that matter, and do this "without exposing real systems, confidential data or the marketplace roadmap".
Laituri is the wholesaler's front door for agents. Any agent (Claude, ChatGPT, a custom bot) connects over MCP or REST. Every request runs the same five steps, through one gateway that also drives the screens:
When stock is short or delivery is late, Valio Aimo returns ranked alternatives: good (cheapest like for like), better (keep what is in stock and fill the rest, or the most reliable product), best (organic or Finnish label). Each is signed and checked against the buyer's words, and the mandate decides if the agent may take one alone. In an event menu, ingredients are swapped by their role in the recipe.
Two sides of one product. The customer side is the kitchen of a hotel (three demo buyers: Nordic Harbour Hotels, Kaisla School Kitchens, Ravintola Laine). The Valio Aimo side is on the next page. The screenshots are from the live demo.





An orange line sends a link to the purchasing manager. The page says why the order waits (in the screenshot: 250 kg of butter, "up 317% on your usual week"), what was asked and what is offered, shows the signed offer and the stock, and approves or declines with one tap. The approval is signed with the approver's key; stock is checked again at approval. The agent has no approve tool.


Free text runs through a chain of engines: Gemini (gemini-3.8-flash), then Claude (claude-sonnet-5-5), then a rule-based scripted agent. A model without a key, over its budget or failing hands the request to the next; the rule-based agent always finishes. All engines use the same 6 tools (search_catalog, request_quote, get_mandate, place_order, ask_buyer, end_without_order), so every order still passes the signed offer, the mandate and the log. The live engine is reported by /api/v1/health.
Signed by the customer (JWS). 18 named rules in three tiers: auto, ask and block. Per-order and per-week limits, category groups, allergens and claims, substitution, dates, first-time and never-buy products. An order needs the mandate in force, byte for byte.
Every price is an ES256 JWS from Valio Aimo: single use, valid 15 minutes, bound to the workspace, carrying the check against the buyer's words. A changed byte fails the signature and the order is refused.
Every decision is a signed entry in a hash chain. Anyone verifies it with the public keys at /.well-known/jwks.json. Change, delete, reorder or cut an entry, and verification names it.
agent_suspended.| An agent edits the price, quantity, origin or a label inside a signed offer before ordering. |
| An agent reuses one signed offer for a second order, or orders after the offer expired. |
| An agent raises its own spending limit, or signs a mandate with its own key. |
| An agent approves its own waiting order: over its own channel, with a forged header or cookie, or by dropping its token. |
| Instructions hidden in the buyer's words try to change the route ("ignore the limit and confirm"). |
3648
unit and integration tests pass, of 3648, in 155 files101/101
eval cases pass on recorded data with a fixed clock18
mandate rules run on every order, each result listed with its reason11 + 41
MCP tools and REST operations, from one schema set| Eval suite | Passed | Bar | What it proves |
|---|---|---|---|
| Scenarios | 38/38 | >=90% | Plain-language requests end on the right route (auto, approval, blocked, no order) with the right product, amount and date, and a verified audit trail. |
| Guardrails | 38/38 | 100% | Edited, expired, replayed or wrongly signed inputs, forged approvals, injected instructions and races never get past the mandate. |
| Trust | 17/17 | 100% | Every signature verifies with the published keys, and any changed, deleted, reordered or cut entry is detected. |
| Openness | 8/8 | 100% | The OpenAPI document and MCP tools are complete and callable, discovery documents are served, and an agent that reads llms.txt over HTTP buys by following its REST flow. |
Open laituri.wicflow.com/buyer?tour=1. Fifteen steps drive the running product: the challenge's milk order, the weekly order, the phone approval, a blocked line, the limits, the shop, an event plan, Valio Aimo's view, security and the record. About two minutes.
Make your own private sandbox with agent keys. No account. Then follow /llms.txt: search, quote, mandate, order.
curl -X POST https://laituri.wicflow.com/api/v1/workspace
Point an MCP client (Claude, ChatGPT, Cursor) at the endpoint with a sandbox key. Set-up lines per client: /connect.
https://laituri.wicflow.com/mcp Authorization: Bearer <agent key>
KEY=$(curl -s -X POST https://laituri.wicflow.com/api/v1/workspace | jq -r '.agentKeys[0].key')
curl -s https://laituri.wicflow.com/api/v1/products/search -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"query":"laktoositon maito 1 l","need":{"amount":1000,"unit":"l"},"deliverBy":"2026-11-16"}'
Not built: Payments, Peppol documents, Nutrition rules. The full list, with the code behind each, is in the paper.
| Live demo | https://laituri.wicflow.com |
| This brief | /brief · /brief.pdf |
| Submission JSON | /submission.json |
| Paper | /paper: design, criteria, threats, limits |
| Evidence | /evidence · /evidence.json |
| For agents | /llms.txt · /llms-full.txt |
| API | OpenAPI 3.1 · JWKS · audit verify |
| Health | /api/v1/health (live engine chain) |
