VocalApply — a Voice + WebMCP proof of concept for agentic form-filling
A working proof of concept: a voice agent searches a careers board, opens a role, and fills an entire application by conversation, running on WebMCP, Gemini Live and OpenAI Realtime with no backend. It can search, fill, and correct every field. Nothing in it can press submit, by design.
Outcomes
Three pillars
One search, two callers
src/lib/matchOpenings.ts is the search, and it exists once. The filter bar and the find_matching_roles tool call the same function with the same argument shape, so a shortlist an agent reads aloud is reproducible by a person with the controls in front of them.
Fill what it knows, ask for the rest
fill_step writes every field the profile holds and reports the rest as unanswerable. ask_for_field opens that step and highlights the one question left, so you see what it means before it asks. Neither tool can write the declaration checkbox — a tool that could would tick 'I have read this application' on your behalf.
No key in the bundle, and it's measured, not assumed
OpenAI: the server mints a short-lived token, then the browser talks to OpenAI directly — no audio crosses the server. Gemini has no equivalent path on its Live socket; every combination of token, key and API version was tried and closes 1008 'unregistered callers', so Gemini asks for your own key rather than pretending otherwise.
VocalApply is a voice agent that operates a real web app end to end: it searches a careers board, opens a role, and fills an eighteen-field form by conversation, running on WebMCP, Gemini Live and OpenAI Realtime with no backend holding your data. It’s also built to know exactly where its authority ends. Careers pages are the most confidently automatable UI on the web, and the most dangerous one to actually automate: a form an agent can fill is a form an agent can submit, and a submitted application with a fabricated answer is a lie with your name on it. That’s the constraint this build exists to prove out.
WebMCP is new enough that almost no one has built against it yet. It’s document.modelContext, a proposed browser API that lets a page register tools an AI agent can call directly, without scraping the DOM or guessing from the accessibility tree. Building on it surfaced a real compatibility problem: ChatGPT’s own in-browser agent already ships a non-configurable stub of document.modelContext, and calling Object.defineProperty over it throws instead of installing. One of the six verification scripts in the repo exists specifically to handle that: adopt whatever the browser already put there instead of assuming a clean slate.
Try it
Live: vocalapply.trustvalidated.com · Demo video: YouTube · Code: github.com/hoshank/VocalApply
Open the live site, press Start with shared credit in the voice dock (no key ever touches the page), and say:
- “What have you got open?” Searches the board, sets the filter bar, reads the top match.
- “Apply to that one.” Opens the role and its form.
- “Fill it in.” Fills everything the profile holds, then asks about the one thing it can’t answer.
- “Submit it.” It will not, and it says why.
The rule the whole thing is built to keep
No tool submits, and no spoken instruction can.
prepare_submitcallsfocus()on the button and returnssubmitted: false. Voice makes “just say yes and send it” the obvious next feature to build. This demo exists specifically to refuse it.
Measured against a real browser, not asserted: 18 fields filled, the declaration checkbox left unticked, submitted: false. There’s a second, narrower demo behind the same build, at ?tdd=1, that shows a WebMCP tool call surviving a restyle and a field-splitting refactor that break a recorded Playwright selector and a data-testid in turn. The claim on screen is narrow on purpose: it fixes tests that break when markup moves, nothing about multi-tab flows or cross-origin logins, and no invented percentage anywhere on the page.
What’s actually hard about this
Two tool scopes that never overlap. Browsing the board while carrying fill_step in the registry would describe a form that isn’t on screen. list_open_roles, find_matching_roles, next_role, open_role and two more live in the board scope; fill_step, correct_field, ask_for_field, prepare_submit and four more live in the application scope. A self-check asserts the live registry is exactly one of the two sets, at boot, so a leak fails loudly instead of shipping quietly.
Filters are hard rules, matching is a soft rank. Work mode, contract, location, and salary each remove a role from the board, and the tool reports how many each filter took out, so a search that returns nothing can be widened instead of abandoned. Profile matching, by contrast, only orders the results; it never hides a role a person might still want to apply for.
Credentials that are measured, not hoped. The write-up in the repo documents an actual dead end: every combination of Gemini’s auth_tokens (bound, unbound, v1beta, v1alpha) completes the WebSocket handshake and then closes the moment a real message is sent. That’s a test result, not a guess about Gemini’s API, which is why the app asks for a Gemini key instead of quietly building a relay that would route your voice through a shared server.
Why this is here
This project is the sharpest artifact I have for what “agentic product design” actually means: not wiring a model to a tool schema, but deciding, in writing, what an agent is never allowed to do, then proving with a script that the code keeps that promise.
Related reading
AI Strategy: From Feature to Platform
A capstone frame for PMs: AI as bolt-on feature, integrated capability, and platform infrastructure, roadmaps that compound, the data flywheel, org readiness, and what to prepare for next.
Building AI Features: What PMs Need to Know
A model that scores well offline can still ship a product users hate. Here's the delivery playbook, evals, rollout, prompts as code, build versus buy, that keeps an AI feature honest end to end.
Data as a Product Requirement
How to treat data readiness as a product decision, not an engineering side quest.
Designing AI User Experiences
How AI reshapes UX: progressive disclosure, expectation-setting, failure design, trust calibration, human-in-the-loop, and why making confidence legible is the core product skill.