Inspiration

When we entered the WebMCP Challenge, our honest goal was to check what we could do with it. The showcase examples were mostly agents filling shopping carts and forms — useful, but one-directional: the agent acts, the page obeys.

Meanwhile, every AI tutor we knew worked beside an educational tool, never inside it. The learner plays with a simulation, then manually types what happened into a chat; the model reasons from a stale summary and, worst of all, happily does the thinking the student was supposed to do.

That combination suggested a question: what if the tutor lived inside the lab page itself — reading the same live bench, proposing evidence, but structurally unable to take over the scientific method? A tutor that is bidirectional: the agent sees what the learner actually did, and the learner sees and approves everything the agent actually proposes. LabMate is our answer.

What it does

LabMate is a 15-minute high-school physics inquiry around one LED circuit, following the scientific method: Predict → Design → Evidence → Reflect.

  • The learner states a prediction ("if resistance decreases, the LED gets brighter because current increases") and locks it. The hypothesis and the final conclusion are learner-owned: visible to the agent, writable by no tool.
  • Through WebMCP, the agent sees the exact live bench — voltages, saved trials, the current stage, model limits, and the page's revision number. It proposes one fair experiment at a time. The proposal appears as a preview card and touches nothing until the learner approves, edits, or rejects it.
  • The demo's climax is a confound challenge: the learner changes the voltage from 5 V to 9 V after the agent last looked. The agent's now-outdated proposal is rejected atomically (stale_revision), because it was written against a world it never observed. The agent re-inspects, spots the second variable, and proposes a revised trial that restores a valid controlled comparison.
  • Once a controlled pair exists, the page compares trials and reports the valid pairs. The learner — not the agent — answers four reflection prompts (what changed, what stayed constant, what the measurements show, whether the prediction was supported) and locks the conclusion.

Under the hood, the simulation is a conceptual teaching model: $I = V/R$, $P = V \times I$, LED brightness bands keyed to current, and six trial slots — of which the agent may fill at most four, so one slot is always reserved for the learner. Every accepted mutation increments a shared revision and records a Human/Agent receipt, so the collaboration is auditable. And when document.modelContext is unavailable, the status chip flips to LAB READY and the whole lab still works in a regular browser.

How we built it

The app is a static front end: React 19, TypeScript, Vite, Zustand, Tailwind CSS with shadcn-derived controls. No database, no login, no OpenAI API calls, and deliberately no custom chat surface.

Everything — human clicks and agent tool calls — flows through one revision-safe command layer: gates → validation → revision + 1 → a single atomic state update → a receipt. The agent's three Site tools are thin views over those same commands:

  • inspect_experiment() — the only read-only tool; returns the full experiment snapshot.
  • propose_trial(...) — the approval gate; creates a visible preview card, not evidence.
  • compare_trials(...) — surfaces controlled pairs.

Two discipline points we refused to compromise on: every tool schema rejects extra fields (additionalProperties: false), and actor is never accepted from the model — the registration adapter pins it to agent. Failures are structured codes (hypothesis_required, approval_required, student_slot_reserved, stale_revision, trial_limit_reached…), never prose, so the agent can actually replan from them.

For quality: 26 Vitest unit/contract tests and 3 Playwright flows, including a document.modelContext shim that lets us test the full agent loop headlessly — plus a live run in ChatGPT's desktop browser. typecheck, test, test:e2e, build, and lint are all green.

Challenges we ran into

Trust by construction. The hardest question wasn't "how does the agent help" but "how do we guarantee it can't write the conclusion?" Our answer is structural: learner-owned fields exist in the page state but in no tool schema. There is nothing for the model to call.

Two authors, one page. Human and agent mutate the same state concurrently. Optimistic concurrency (expected_revision) makes stale writes fail atomically — but making that rejection legible, so the agent understands "the world changed, look again," took real schema and prompt design.

A deterministic demo with a probabilistic actor. Our centerpiece moment depends on the model doing the right thing on stage. We shaped the tools (one-proposal-at-a-time, structured errors) and the demo prompts so the inspect → propose → human-intervenes → stale-rejection → replan loop happens reliably.

Testing without ChatGPT. CI can't drive the desktop app, so we mirrored document.modelContext in a Playwright shim and contract-tested the adapter against it.

Honest scope. The simulation is a conceptual teaching model: overloaded is a teaching warning above 20 mA, not a real component rating, and forward voltage, tolerance, and temperature are intentionally omitted. The page always says so.

Accomplishments that we're proud of

  • The full loop runs live in ChatGPT's built-in browser: agent proposes → learner approves → human changes the world → stale proposal rejected → agent re-plans → learner concludes, with a receipt for every step.
  • The agent is useful because it is constrained: one proposal at a time, a trial quota that always leaves the learner a slot, and zero silent writes.
  • The lab never depends on the agent: in a plain browser, the pedagogy stays intact.
  • The quality gate is green end-to-end: 26 unit/contract tests, 3 e2e flows, typecheck, build, lint.

What we learned

  • Treating the page as the source of truth turns tool design into contract design. Structured error codes beat chat prose for agent replanning.
  • Human–agent experience is mostly a state machine: who may write what, when, and what happens when the world changes under the agent. Getting that machine right is the product.
  • Strictness is what makes trust possible: additionalProperties: false and a pinned actor are the difference between learner control as an aspiration and as an invariant.
  • "The agent may only propose" felt restrictive at first — it turned out to be the feature. It kept the experiments fair and kept the student thinking.

What's next for LabMate

  • More missions on the same Predict → Design → Evidence → Reflect skeleton — optics, kinematics, reaction rates — with teacher-authored content.
  • A classroom view so teachers can see receipts, common confounds, and where students get stuck.
  • Extracting the pattern: learner-owned fields, approval gates, revision-safe commands, and agent quotas generalize beyond this lab, and we want to package them for other "human-owned page, agent coach" sites built on WebMCP.

Built With

Share this project:

Updates

Submission history