A weekly local edition for every store in a chain, built from the taste of each block (Qloo + NVIDIA Nemotron on Nebius).
Live demo: https://localedition.pages.dev
- Open https://localedition.pages.dev and press Open the sample chain. You land on a map of Kettle & Kiln, a sample coffee chain with eight stores at real New York corners.
- Press Build this week's editions and watch the agent work store by store (tool calls, models, tokens and cost stream in live).
- Open any store: the front page has four items with their evidence (open the evidence drawer). Press Approve all, then open the staff card.
- Optional: Connections shows Square, Slack, Gmail/Outlook and the calendar feed;
/proofand/limitsshow what ran, on which model, at what cost, and every budget.
For each store, once a week, the agent builds an edition from that block's taste:
- Special: one new drink or bite, taken from the chain's own menu (read from a Square catalog, a photo of the menu board, or a CSV), tuned to the block.
- Sound brief: what to play in the room, with artists that skew local.
- Local partner: a neighbouring place worth a tie-in, with an offer idea.
- Event night: something to host that week, tied to a real local event when one is found.
Every item carries evidence (source, endpoint, numbers) and an item without evidence is dropped, never shown. A Nemotron 3 Ultra reviewer checks the whole chain for near-identical stores. Head office approves on a map of all stores; approved editions become a one-page staff card (phone first, public link) for each store.
Each connector is built and tested against the providers' documented API shapes (196 unit tests across the Square, Slack, Gmail/Outlook and calendar code, with provider calls faked). The Composio auth configs for Gmail and Outlook exist. No live sandbox or test account is connected yet: there are no Square or Slack credentials on the deployed app and no Gmail consent, so on https://localedition.pages.dev none of the three has run against its real provider.
| Tool | What it does here | Tested against | Live on localedition.pages.dev today |
|---|---|---|---|
| Square | Two ways: imports the menu (locations become stores); approving a special publishes it back; signed webhooks update the app; sales per special are read back. OAuth or a token. | Square's documented API shapes; sandbox connection pending. | No |
| Slack | Head-office digest with Approve and Regenerate buttons (signed interactions), staff cards to a store channel. | Slack's documented payloads and signing; test-workspace connection pending. | No |
| Gmail / Outlook (via Composio) | The staff card is emailed to the store; replies from managers are classified (sold out, sold well, change request, problem, other) and become suggestions for next week's build. Needs a consented mailbox. | Composio's documented API shapes; auth configs exist, no mailbox consented yet. | No |
| Calendar feed | A private .ics link per store with its event night. Needs no external account. |
Unit tests on the feed. | Yes |
| Technology | What it is | What it does here |
|---|---|---|
| Qloo Taste AI | A cross-domain taste and affinity API. | The block profile: what the people near each store lean toward, and how that differs from the city. Endpoints used (host hackathon.api.qloo.com): GET /search (find brands the chain resembles), GET /v2/insights (block tags, nearby artists, brands and places, heatmap, rising taste), GET /v2/trending (what is rising), GET /v2/analysis/compare (two stores side by side). No customer or personal data is ever sent: only coordinates, entity ids and tag urns. |
NVIDIA Nemotron 3.5 Super VL (nvidia/Nemotron-3.5-Super-VL) |
A vision-language model with tool calling. | The agent loop that plans each edition and calls tools, and the menu-board photo reader. |
NVIDIA Nemotron 3 Ultra (nvidia/Nemotron-3-Ultra-550b-a55b) |
A large reasoning model. | The reviewer: judges every store's edition against the others and asks for a regenerate with a hint. |
NVIDIA Nemotron 3.5 Lightning (nvidia/Nemotron-3_5-Lightning) |
A fast, cheap model. | Copy for items and staff cards, Tavily event triage, the live self-check, and classifying email replies. |
Qwen3 Embedding 8B (Qwen/Qwen3-Embedding-8B) |
A text embedding model. | Matches menu items and nearby places to each block's taste, and finds near-identical items across stores (cosine clash). |
| Nebius Token Factory | OpenAI-compatible inference for open models. | Serves every model above. |
| NeMo Guardrails 0.24.1 | NVIDIA's guardrails library. | Certifies every item (a custom health-claim rail, prompt-injection stripping, and NeMo's self check output rail on Lightning) and runs a red-team eval. It runs in a Nebius Serverless Job (jobs/, guardrails/) that is started from the CLI on demand, with npx tsx scripts/nebius-job.ts certify eval. It is not on a schedule: Cloudflare Workers cannot reach Nebius's control plane (it answers Cloudflare egress with a 522, see docs/NEBIUS-REST.md). Results are posted back signed and show on /proof as manual runs. The live path in the Worker (every head-office edit and every build) uses a TypeScript mirror of the regex rails plus the Lightning self-check, and marks items checkedBy: live. |
| Tavily | A search API for agents. | Search and extract for this week's local events near each store; crawl of the chain's own site to draft the brand voice. |
| Cloudflare | Workers, Pages, D1, KV, R2, Durable Objects, Workflows, cron. | Worker via OpenNext fronted by Pages; D1 for data; KV for provider caches; R2 for menu photos; Durable Objects for the spend meter, build lock and call ledgers; Workflows for builds (one retried step per store); cron every Monday 00:00 UTC for the weekly rebuild, which runs on Token Factory and Tavily only. |
flowchart LR
V[Head office browser] --> P[Cloudflare Pages front]
P -->|service binding| W[Worker: Next.js via OpenNext]
W --> D1[(D1)]
W --> KV[(KV cache)]
W --> R2[(R2 menu photos)]
W --> DO[Durable Objects: spend, locks, Qloo and Tavily ledgers]
W --> WF[Workflows: EditionBuild, WeeklyRebuild]
CRON[Cron: Monday 00:00 UTC] --> WF
WF --> A[Agent loop]
A -->|Super VL, Ultra, Lightning, Qwen3 Embedding| TF[Nebius Token Factory]
A --> Q[Qloo Taste AI]
A --> T[Tavily]
A --> G[Live guardrails: regex rails + Lightning self-check]
W <--> SQ[Square]
W <--> SL[Slack]
W <--> CO[Composio: Gmail / Outlook]
CLI[Developer CLI, on demand] -->|nebius ai job| NJ[Nebius Serverless Job: NeMo Guardrails 0.24.1]
NJ -->|signed results| W
- Spend cap:
SPEND_CAP_USD(default $5) on Token Factory, enforced in one Durable Object with reserve-then-settle. Each visitor workspace gets a $0.40 sub-budget and each network a $0.80 daily cap; $1.50 is reserved for the demo workspace and the weekly job. - Qloo call ledger: at most 300 live calls in total and 40 a day across all visitors, reserved before each call and never refunded, plus a 14-day response cache. Regenerate never reaches Qloo.
- Tavily ledger: one global ledger of 80 credits in total and 10 a day, results cached 7 days; live search is limited to the demo workspace's unmodified sample stores and chain setup.
- Rate limits per workspace and per IP on builds, regenerate, staff cards, edits, menu reads, brand search and brand-voice drafting (the table is on
/limits; the code issrc/server/limits-table.ts). - At most 60 new workspaces an hour; workspace data expires.
- Kettle & Kiln is sample data, labelled so in the app. It is not a customer.
- Square, Slack and Gmail/Outlook are not connected on the live app yet (see the connectors table); only the calendar feed runs without an account.
- Qloo: live-only in production. Every Qloo result comes from a live Qloo call or a saved real answer (KV, 14 days); replay, fixture and recording fallbacks are unreachable there, and a failed call shows a retry state, never sample data. Calls go through a hard ledger (2,000 through 15 Dec, 200 a day). Real Qloo responses are never committed. Fixtures under
fixtures/qloo/exist for unit tests andnext devonly. - NeMo Guardrails runs only when someone starts the job from the CLI; the weekly cron does not call Nebius.
- The first live Tavily prefetch of a week can take longer than the agent's 25 s tool timeout; the work finishes and is cached.
docs/holds working notes and smoke-test records from the build;docs/CONTRACT.md,docs/CLOUDFLARE.mdanddocs/DEPLOY.mdare the reference ones.
npm install
NEXT_PUBLIC_DATA_MODE=mock npm run dev # UI on typed mock data, no server calls
npm run dev # DATA_MODE=app: real routes; providers default to replay/fixture without keys (never in production)Open http://localhost:3000. Add NEBIUS_API_KEY, TAVILY_API_KEY and QLOO_API_KEY to .env.local and set TF_MODE, TAVILY_MODE, QLOO_MODE to live to use real providers; .env* is gitignored. scripts/deploy.sh and scripts/deploy-secrets.sh deploy to your own Cloudflare account and read credentials through a local ~/.secret-store/inject.sh helper, so adapt them to your own secret handling.
npm run typecheck && npm run lint
npx vitest run # 115 files, 1360 tests
npm run e2e # Playwright (starts next dev)
cd guardrails && python3 -m pytest -q # NeMo rails: 115 passed, 1 skipped
python3 -m pytest -q tests/e # job scripts: 12 passedMIT, see LICENSE. Copyright 2026 JoelOnBeat.