A supervision surface for agents that act.
NextWave Hackathon 2026 · CDMX · Challenge 3 — The Interface That Builds Itself
usedonald.com — no install, no signup, nothing to run.
Five runs, five different shapes, one protocol:
| Run | What it shows |
|---|---|
| Berríos OP-4471 | the full case — an ambient watch hands off to a triggered chain when the carrier reroutes a vessel, and a human gates the action |
| Berríos OP-4471 · v2 | the same case with the operational-stage renders |
| Missing invoice | a cross-domain investigation: supplier invoice vs. purchase order, an exact $840 gap, our error |
| Replan | new evidence arrives mid-flight and the graph rewires itself |
| Land pickup | a scheduling conflict resolved without interrupting anyone |
These five play from event recordings bundled into the app (frontend/lib/donald/events.*.jsonl),
replayed through the exact same reducer and components as the live path. That is deliberate: the
demo has no backend to be down, no database to migrate and no bill to pay, so the link works
forever.
The live half — an agent reporting over MCP into MySQL, and an operator stopping it mid-run — is real code in this repo, but it is not currently hosted. Run it yourself with Self-hosting the live stack.
Companies like Nauta sell AI agents that do more than alert: they execute. They send emails, book trucks and dispute invoices, 24/7. Their own website says it plainly:
“Agents that do not send an alert and wait. They act.”
That leaves a gap:
| An agent that only alerts | The person reads, decides and acts. The person remains in control. |
| An agent that acts | Things happen without them. How do I trust something that has already acted? |
An agent that only alerts can be audited by reading the alert. An agent that acts needs a window — and a brake.
Donald is that window and that brake. The operator watches the agent's reasoning build itself on screen as it happens, and can stop or redirect it.
We change nothing about the provider. Its stages, logic and actions stay intact. We only ask the agent to expose its intent and report when that intent changes.
Any agent that speaks these five verbs becomes supervisable:
| Verb | The agent says | Donald draws |
|---|---|---|
| DECLARE | “I propose these N steps” | staggered gray nodes |
| ADVANCE | “I am on step 3; this is what I found” | the node pulses and the edge draws itself |
| REPLAN | “The plan changed: remove this, add that” | the graph rewires itself |
| ASK | “I need you to decide” | the node expands into a decision panel |
| FINISH | “I am done; this is what happened” | the run collapses into a summary |
What we ask for is a proposal, not a commitment:
“We know you have a lot to do. Just propose your plan — even if it changes.”
A changing plan is not failure; it means the agent learned something. If the plan never
changed, the interface would never rebuild itself and there would be nothing to demonstrate.
That is why every replan carries its cause (reason, triggered_by, evidence) — without it,
the change looks like a mistake; with it, the system looks like it learned.
ANY REAL AGENT skill/ ← teaches the agent the domain and reporting loop
(any MCP client) │
│ MCP · 5 verbs · <mcp-host>/v1/mcp
▼
backend/donald/ ← Go generated by nuzur + MCP server
│ entities: agent_run · agent_node · agent_edge
│ agent_event · intervention · artifact
▼
<api-host>/v1/ ← REST + live event stream
│
▼
frontend/ ← Next + React Flow. Snapshot + SSE deltas; the graph
shape is computed from the edges, never hand-authored.
| Folder | What it is |
|---|---|
backend/donald/ |
Go backend generated by nuzur from the v2-run-graph-events model, plus the MCP server in app/mcp/. Generated files are not edited — see backend/donald/AI.md. Custom work belongs in app/. |
frontend/ |
Next 16 + React Flow. Graph positions are calculated from data, never hand-authored. |
skill/ |
donald-flow teaches any agent to report through MCP; nauta-operations gives the demo agent a coherent importer data landscape. |
deploy/ |
Helm charts for the deployed API, MCP endpoint and web surface. |
The live topology is one host running microk8s. The same container image runs twice — DONALD_ROLE=mcp serves
agents, DONALD_ROLE=api serves browsers — so a slow agent cannot degrade the graph someone is
watching. Green is the agent writing, blue is reading and serving, red is the operator pushing back.
The red path is the whole product: an operator's stop or steer is written as an event, picked up by the
agent on its next check_instructions, and honoured by changing the plan. It is advisory — these
agents are not ours to kill — and the interface says so rather than pretending otherwise.
Nine entities. agent_event is the source of truth — append-only, with a per-run monotonic
sequence and a unique idempotency_key. Everything else is a materialised snapshot of it:
agent_node and agent_edge exist so a client can start without replaying the whole log, and can be
rebuilt from it at any time. agent_event_payload and intervention_interaction are dependent
entities — typed JSON, not bare columns.
Node 20+ is the only prerequisite. There is nothing else to install and no service to sign up for.
git clone https://github.com/RodMed0709/nextwave-hackathon.git
cd nextwave-hackathon/frontend
npx pnpm@10 install
npx pnpm@10 dev # http://localhost:3000On Windows PowerShell use npx.cmd instead of npx.
Open http://localhost:3000 and the five recorded runs replay locally — no environment variables, no API keys, no backend. That is the whole tutorial.
Two optional keys unlock two optional things:
| Variable | What it turns on | Without it |
|---|---|---|
OPENAI_API_KEY |
typed and spoken operator instructions get interpreted; prompt suggestions appear | the buttons are there; instructions are recorded verbatim |
NEXT_PUBLIC_DONALD_API |
any run key that is not one of the five recorded ones streams live from your own backend | every run key falls back to a recording |
Put them in frontend/.env.local (gitignored — copy frontend/.env.example).
Verification gates, all three green on main:
cd frontend
npx pnpm@10 exec tsc --noEmit # types
npx pnpm@10 test # 112 tests
npx pnpm@10 build # production buildThe frontend is a stock Next 16 app, so any Next host works. On Vercel:
npm i -g vercel
cd frontend
vercel --prod # root directory: frontendLeave NEXT_PUBLIC_DONALD_API unset and the deploy is self-contained: recordings only, no
backend, free tier, nothing that can fall over.
The live path needs the Go API, MySQL and the MCP server. Everything to run them is in the repo —
backend/donald/Dockerfile, the schema in deploy/schema.sql, and the Helm charts in
deploy/ for a Kubernetes host. On a PaaS such as Railway or Fly the shape is:
- Provision MySQL, load
deploy/schema.sql. - Deploy
backend/donald/Dockerfiletwice from the same image —DONALD_ROLE=apifor browsers,DONALD_ROLE=mcpfor agents — so a slow agent cannot degrade the graph someone is watching. Config template:deploy/prod.yaml.example. - Set
NEXT_PUBLIC_DONALD_APIon the frontend to the API's URL and redeploy. - Point your MCP client at the MCP service's
/v1/mcp.
Note the backend is generated by nuzur from the v2-run-graph-events model;
generated files are listed in .nuzur-codegen-manifest.json and must not be hand-edited. Custom
code lives in backend/donald/app/. See backend/donald/AI.md.
Connect a real agent — see skill/README.md. Once your own MCP server
is up, add it as a streamable-HTTP server — the demo build ships with no authentication, so put it
behind one before exposing it:
{ "mcpServers": { "donald": { "type": "http", "url": "https://<your-mcp-host>/v1/mcp" } } }Give the MCP client both donald-flow and
nauta-operations. Then type any operational request, for example:
“L'Oréal's invoice does not match our PO. Find out what happened and draft the right email.”
The provider in this demo is a real agent reading those skill files. There is no scenario selector: the input is whatever the operator types, the agent chooses its own plan, and the graph is non-deterministic because it is built from the steps the agent actually takes.
Each produces a different shape on screen. That is the proof that the interface comes from the work, not from a script. These are examples, not presets.
| Case | Example request | Shape |
|---|---|---|
| It stays quiet | “What is the status of OP-4471?” | Routine checks collapse into a line. No needless interruption. A system that always shouts is as useless as one that is blind. |
| It replans and asks | “Handle the transshipment on OP-4471.” | Unplanned transshipment · $3,780 demurrage exposure · invalidated BL. The graph rewires itself and a decision panel appears. |
| It crosses domains | “Why does L'Oréal's invoice disagree with our PO?” | Supplier invoice · missing amendment · exact $840 gap · our error. Different evidence and steps, zero new frontend code. |
The third case proves the system is open-ended: it was added by expanding the agent's knowledge, without writing a new flow or changing the frontend.
The steps unfold while a real agent reads, reconciles, calculates and decides what comes next. That is not decorative delay:
Duration is the intervention window. You can only stop something that is still happening. If every step completes instantly, the stop button is decoration.
The graph stays current as the agent works: progress appears when something takes time, a block is visible when the agent needs missing data, and a replan appears the moment new evidence changes the work. The timing belongs to the task, not to a prerecorded sequence.
docs/donald-architecture.png |
Deployment and data flow — pods, database, ingress, and the intervention path |
docs/donald-domain-model.png |
The nine entities and their relationships, as modelled in nuzur |
PROBLEM.md |
The operator (Jorge, 52), the thesis, the metric and the anti-scope |
DECISIONS.md |
The engineering decisions, the alternatives we rejected, and why |
PITCH.md |
The pitch script, minute by minute, with the hard Q&A |
CONTEXT.md |
The boundary with Nauta, agent skills and the ui_spec vocabulary |
skill/README.md |
How to connect an agent to Donald over MCP |
skill/nauta-operations/SKILL.md |
The importer world the demo agent can investigate |
backend/donald/AI.md |
Which generated backend files are editable and which are not |
The demo is live and permanent; the live stack is self-host.
usedonald.com is the frontend/ directory deployed to Vercel with no
backend attached. The five runs replay from bundled recordings through the production reducer and
components, so the link cannot go down, cost anything, or drift from the code on main.
✅ frontend deployed, permanent, zero-dependency — the five runs replay from recordings
✅ every run has its own shareable URL, handed to the agent at start_run
✅ donald-flow + nauta-operations skills, ready for any MCP client
✅ Go backend + REST API + MCP server + schema + Helm charts, all in this repo
⚠️ the hosted API and MCP endpoint are OFF — self-host them to get live runs (see above)
⚠️ no authentication in the demo build: anyone who reaches the MCP endpoint can write runs
⚠️ artifact byte uploads need R2 credentials; links and inline text work today
⚠️ demo pacing (`DONALD_DEMO_PACING`) exposes a `wait` tool; turn it off before production
The deployment diagram above describes the live topology — one host, two roles off one image,
MySQL behind them. It is what deploy/ builds, and what you get by following
Self-hosting the live stack. It is not what serves usedonald.com
today.
https://usedonald.com/runs/<run_key> |
one run, watched live |
<api>/v1/runs |
run list, newest first |
<api>/v1/runs/<run_key> |
snapshot + last_sequence |
<api>/v1/runs/<run_key>/stream?after=N |
SSE deltas after a cursor |
<mcp>/v1/mcp |
the agent-facing MCP server |
start_run returns a watch_url, and the skill tells the agent to show it immediately:
Follow along:
https://usedonald.com/runs/sess_8f21
The URL is built from the agent's own run_key, so it is known before a single step has run.
A link produced at the end is a link nobody opened.
- Runs recorded before a fix keep the gaps that fix closed. Graph structure is reconstructed from the event log, so a run whose events predate an improvement renders the way it was recorded. Re-run it rather than expecting a repair.
- Interventions are advisory. The agents are not ours to control, so a stop reaches the agent
on its next
check_instructionsand it complies if it can. That is honest supervision, not a kill switch. - Demo pacing is on (
DONALD_DEMO_PACING), which exposes awaittool so runs unfold at a readable speed. It must be turned off before production — an agent should never be able to park a request on the server.


