Your product has a second audience.
The humans who click and type, and the AI agents that now use and find products on their behalf.
We build the layer that serves both, without degrading either.
This is not about how fast you ship.
That is the other service. The Frontend Delivery Factory points inward and changes how your organization ships. Frontend AI points outward and changes what your product does once it is shipped.
The test is one sentence. If good ideas queue behind a small Frontend team, you want the factory. If your product needs to do something it cannot do yet, for a user or for an agent, you are on the right page.
AI your users feel, not AI you announce.
Production features in your repo, in your components, behind your auth. We ship the surface and the plumbing under it: evals, observability, fallbacks, and structured output so a bad response is a caught error rather than a broken render.
Generative UI
Interfaces that assemble around the request instead of routing to a fixed screen. Typed, streamable and accessible components rendered from your own design system, wired to the same data and permissions as the rest of the product.
In-product agents
Assistants that run on your data and drive real product actions, not a text box that answers and stops. Tools are typed, scoped to the signed-in user, and permitted by the same rules your UI already enforces.
Voice and conversational flows
Realtime voice surfaces where speaking is genuinely faster than clicking. Voice-to-action rather than voice-to-transcript, with the same guardrails and fallbacks as every other surface.
Document and content intelligence
Extraction, classification, summarization and smart search over the material your users already upload, returned as structured data your product can act on rather than prose someone has to re-read.
An agent cannot click your interface.
It resolves what you are, reads what it can, and then looks for an action it can call. Most products stop at the second step, so the agent summarizes a competitor and completes the task somewhere else. None of that arrives in your analytics as a lost session. It does not arrive at all.
Ranking well does not fix this. The missing piece is an action layer, and that is Frontend work.
MCP apps and MCP servers
Your product inside the assistants people already use, as a real interface rather than a text mention. Enterprise-grade servers on the current stateless MCP spec, deployable on serverless and edge, with SSO-integrated auth, audit trails, rate limits and rich UI responses.
WebMCP tools on your existing app
Safe, typed, structured tools exposed to browser agents on top of the app you already run, so an agent calls a contract instead of guessing at your DOM. Google and Microsoft took WebMCP into W3C standardization, Chrome has it in origin trial and Edge ships it behind a flag, with a polyfill path for everything older.
Agent discoverability
Being findable and quotable when a buyer researches inside an assistant instead of a search engine. Extractable answers, a resolvable entity, rich structured data, retrieval-bot opt-ins, and citation tracking so you measure qualified AI referrals rather than impressions.
Agentic commerce
If your customers buy online, the checkout now has an audience that never sees your UI. A catalog an agent can read without rendering your grid, agent-callable tools for availability and cart, and a checkout completable by a caller with no interface, on the current commerce and payment protocol stack.
Fixed price, defined scope, production code.
Shipped by a scoped project team, by senior engineers embedded in yours, or through a factory already installed on your codebase. We do not bill hourly.
- 01SCOPE
One job, named
We pick the user-facing job worth doing first and the surface that fits it, then write down what shipping it means. Scope, deliverables and a fixed price before any code.
- 02BUILD
In your repo, in your components
No rewrite and no parallel stack. The model layer sits behind an interface of your own, the rendering reuses your design system, and your existing auth and permissions stay in charge of the data.
- 03GUARD
Evals, tracing, fallbacks
Structured output so malformed responses are caught errors. Evals on the behaviors you care about, running in CI. Tracing on every run. Honest degradation in the interface when the model is unsure.
- 04HAND OVER
Your team runs it
The code, the evals, the observability and the decisions behind them stay with you, documented. We are available afterwards because you want us there, not because the feature cannot run without us.
Pick the first thing
your product should do.
One job, scoped and priced before we write anything. That is how every build starts.
Scope an AI buildReady to shift?
We accelerate Frontend delivery. The Frontend Delivery Factory installs the system that lets everyone in your org ship production Frontend.
Senior engineers, AI-native by default, shipping production code in your repo. Fast onboarding. Honest work.
- 01
You send the form.
A few lines on your product and timeline.
- 02
We reply within a day.
Usually faster. No forms after that.
- 03
We meet and plan.
Scope, team fit, start date. Then engineers.
Questions, answered.
The ones that come up once a product team is actually scoping a build: which primitive to pick, how it lands in an existing app, why agent readiness is not SEO, and how an AI feature is kept honest in production.
- A.
Because a chatbot answers and generative UI acts. A text box bolted onto a dashboard asks the user to describe, in prose, something they could have clicked, and then hands back a paragraph they have to act on themselves, so it loses to the existing UI on every task the existing UI already does. Generative UI assembles the interface around the request: ask for churn by cohort and you get the chart, the filter and the export button, wired to the same data layer and the same permissions as the rest of the product. The useful test before we build anything is whether the answer needs a component or a sentence. Jobs that end in a decision need components. If a job genuinely ends in a sentence, we will tell you a chat surface is the right call and keep it small.
- A.
The honest answer is that the choice depends on where your product already is, not on which library is loudest this quarter. For most React codebases the default is the Vercel AI SDK with AI Elements for streaming and tool-use surfaces. assistant-ui and CopilotKit are strong when you want a maintained in-product assistant shell over your own data. Google A2UI is the one to look at when the same generative surface has to render on more than the web. MCP Apps is the right primitive when the interface has to live inside an assistant rather than inside your product. We keep the model layer behind an interface of your own and the rendering inside your existing design system, so the primitive stays a swappable dependency instead of an architecture decision you have to live with. This part of the stack rotates fast, and we design for that.
- A.
No rewrite. We integrate alongside what you run now, in your repo, in your components. The pattern is consistent: scope one user-facing job, pick the surface that fits it (generative UI, in-product agent, voice, or an inline action), wire the model layer with structured output so the response is typed rather than parsed out of prose, connect your data through MCP tools with your existing auth and permissions, and put observability and evals in from the first commit rather than after the first incident. Scoped builds are fixed price against a defined scope, and the first production behavior is deliberately small enough to judge on real usage instead of a demo.
- A.
Ranking and being usable by an agent are different problems, and the second one is a Frontend job. Search ranks documents for a human who will click through and then operate your interface. An agent does not operate your interface. It needs to resolve what you are as an entity, read the page without executing a click-heavy flow, and then find a structured action it can actually call. A site can rank first and still be unusable to an agent, because the action layer is missing entirely. That layer is what WebMCP and MCP servers provide: safe, typed tools on top of the app you already have, rather than an agent guessing at your DOM. The discoverability work (extractable answers, resolvable entity, structured data, retrieval-bot opt-ins) is the readable half. The tools are the operable half. Start with a free AgentReady scan to see which half you are missing.
- A.
Less than a replatform, more than a schema tag. The protocol stack settled during 2026: the Universal Commerce Protocol covers how an agent discovers products and transacts with a merchant, the Agent Payments Protocol carries the authorization underneath it, and both lean on MCP for tool access. What that asks of your Frontend is a product catalog an agent can read without rendering your grid, agent-callable tools for the steps that matter (availability, cart, checkout), and a checkout flow that can be completed by a caller who never sees your UI, without weakening it for the humans who still click. We build those surfaces on top of your existing commerce backend. The reason to look at it now is that this audience does not show up in your funnel as a bounced session. It does not show up at all.
- A.
More than most teams budget for, because the agent is the easy half now. Gartner projects that 40% of enterprise applications will have task-specific agents embedded in them by the end of 2026, up from under 5% in 2025, and the ones that land badly fail in the same recognizable way: a spinner over an autonomous process. The user cannot see what the agent is doing, cannot stop it halfway, and cannot tell a confident wrong answer from a right one, so they stop trusting it and quietly go back to the manual flow. None of that is a model problem. It is a rendering problem. The interface has to stream tool calls while they run rather than reveal them afterwards, let someone intervene at a step instead of only cancelling the whole run, put an approval gate in front of anything irreversible, and say plainly in the UI when the model is unsure. There is a protocol layer for this now and it is worth knowing before you invent your own: AG-UI, which came out of CopilotKit’s work with LangGraph and CrewAI, carries an agent run to the Frontend as an event stream over HTTP, SSE or WebSockets, and Google’s A2UI lets an agent declare the components it wants rendered as structured JSON. We build that layer inside your design system and behind your existing permissions. Decide the autonomy level early, because human-in-the-loop and human-on-the-loop are two different products, not a setting you flip later.
- A.
Less than the headlines suggest and sooner than most teams have it scheduled, because the piece that landed is the transparency layer and the transparency layer is rendered. Article 50 of the EU AI Act applied on 2 August 2026, and it is not the deadline that moved: the Digital Omnibus deferred the high-risk obligations to December 2027 and August 2028 and left Article 50 where it was. Three things fall on the product. A system that interacts directly with people has to make it clear to the person that they are dealing with AI, and clear means at the start of the interaction and in the interface rather than in a paragraph of the terms. Synthetic output, whether text, image, audio or video, has to be marked in a machine-readable format that a detector can read, which is a provenance and metadata problem rather than a badge in the corner of a card. And the deployer-side disclosures, deepfakes, emotion recognition and AI-generated text published on matters of public interest, have to be visible to the person looking at the content. One more date belongs in the calendar: generative systems already on the market before 2 August 2026 were given until 2 December 2026 to meet the machine-readable marking requirement. As Frontend work this is a disclosure surface that lives in the component rather than being bolted on per feature, provenance metadata carried from generation through storage to render so the marking survives an export or an embed, labels that stay legible when the content is displayed somewhere else, and all of it inside your design system so it does not read as a compliance sticker. We build that layer. To be explicit about the boundary: we are not your counsel, we do not classify your system’s risk tier, and we do not issue conformance statements. Bring us the classification your legal team made and we will build what it requires.
- A.
By treating it as a product surface with a failure mode, not a demo with a disclaimer. Structured output with a schema, so a malformed response is a caught error rather than a broken render. Evals on the behaviors you actually care about, written before launch and run in CI, so a model or prompt change that degrades quality fails a build instead of surprising a user. Tracing on every run, so an unexpected answer can be reproduced instead of argued about. Explicit fallbacks and confidence signals in the interface, so the product degrades honestly when the model is unsure. And a scope where the model handles the part it is good at while your existing logic keeps the parts that must be deterministic. Guardrails are what make AI features safe to leave running.
- A.
Less than a rebuild and more than a robots.txt line. Start from what an agent is: a user with your customer permissions, no eyes, no patience for a bundle, and no tolerance for anything that only exists after a hover. Four things follow. First, the same truth has to render for both audiences. If what you sell, what it costs and whether it is available only exist after your JavaScript runs and a carousel settles, an agent either executes your whole application to find out or gives up and summarizes whatever it did parse, which is often a competitor. Server-rendered content and structured data are not an SEO chore here, they are the machine-readable copy of the page. Second, an agent needs actions rather than pages. Scraping a flow you designed for a mouse is fragile for it and unobservable for you, so capability gets declared as tools it can call, through WebMCP in the page or an MCP endpoint beside it, and then the agent transacts through an interface you version and control. Third, the irreversible steps need an explicit gate. An agent that can complete a purchase, cancel a subscription or send a message on someone behalf needs the confirmation to be a real step in the protocol, not a modal it cannot see. Fourth, none of it may degrade the human path, which is the constraint that makes this Frontend work rather than an API project: one product, one design system, two audiences, no second-class version of either. If you sell online there is a commerce layer on top of this (UCP for how agents discover and transact with merchants, AP2 for authorizing the payment), and we build against both.
- A.
You change what you count, because the funnel you have was built for a human who arrives, browses and converts in one session, and none of those three things is true any more. Cloudflare Radar put automated requests at 57.5% of HTML traffic in June 2026, and its May 2026 split had only 9.3% of AI crawler requests coming from search-purpose crawlers, the only category that can produce a citation with a link back. So the majority of the machine traffic reading your product returns no session, no referrer and no event, and the honest thing to say is that your analytics has been getting quieter for a reason that has nothing to do with your product getting worse. What we instrument instead sits in three layers. Retrieval: which agents fetched what, how often, and whether they got a rendered answer or a shell, read from your edge logs rather than from a client-side tag no crawler executes. Representation: whether the answer they can assemble from your pages is actually correct, checked by asking the assistants your buyers use and diffing the answer against what you sell, which is a recurring check rather than a one-time audit because the answers move. Action: agent sessions treated as their own funnel with their own success metric, because an agent that calls three tools and completes a task fires none of the events a human funnel is built on, and averaging the two together hides both. Two honest limits. Attribution from an AI answer to a deal is mostly unavailable today and anyone selling you a clean number for it is guessing, so we report leading indicators and say which is which. And we build the instrumentation and the agent-readable surface, we are not a CDN and we do not sell traffic policy.
- A.
It looks like an interface where the agent’s power is a property of the screen it is on, not of the agent. Five things, and they are all rendering and wiring decisions rather than model ones. First, trust boundaries in the render. Anything the agent read, a support ticket, a scraped page, a PDF a customer uploaded, an email thread, is untrusted content and never reaches the model in the same channel as the user’s own instruction, and never reaches the DOM as anything but data. The failure everyone ships first is a nicely formatted agent response that renders a link, a button or markup that came from the document it just read. Second, scoped tools per surface. The agent on your billing screen gets the billing tools and nothing else, declared where that screen declares them, so a successful injection reaches a small surface rather than everything your API can do. Broad tool access with a clever system prompt in front of it is the pattern that keeps failing. Third, confirmation that names the target. Not "the assistant would like to send an email", but the recipient, the subject and the body, rendered as the thing being approved, because a user who cannot see the actual parameters is approving an intention while the agent executes an instruction. Anything irreversible, anything that spends money and anything that leaves your product gets that treatment. Fourth, provenance in the UI. Show which sources the answer came from and mark which of them were untrusted, so a user can tell a summary of your documentation from a summary of a stranger’s web page. Fifth, a degraded mode you designed on purpose, where the product keeps working with retrieval or tool use switched off, because that is the mitigation the frontier labs themselves ship when something is unresolved. Underneath all five, evals for the injection cases in CI beside your quality evals, so a prompt or model change that reopens one fails a build. What we will not tell you is that this makes the agent injection-proof. It bounds what a successful injection can reach and makes it visible when it happens, which is the achievable goal today.
- A.
A capability inventory and a log, both of which have to exist as build artifacts rather than as a document someone maintains. The inventory is the honest version of "what can it do": every tool the agent can call, which surface declares it, what permissions it runs under, whether it reads or writes, whether it is reversible, and which of them can move money or send something outside your product. Generated from the code that registers the tools, so it cannot drift from what shipped. The permission answer they usually want next is that the agent holds no privileges of its own. It acts as the signed-in user, through your existing authorization, so it can never reach data that user could not open themselves, and a compromised agent session is bounded by that user’s account rather than by your service credentials. The log is the other half: every tool call with its parameters, the surface it came from, the sources in context, the user who approved it if approval was required, and the outcome, retained where your other audit trails live. That is what turns an incident from an argument into a replay. The reason we push for this early rather than at security review is the shape of the 2026 record: the OWASP GenAI Security Project’s Q1 2026 exploit round-up documented eight incidents between 1 January and 11 April with exactly one CVE among them, and the categories most often invoked were prompt injection, sensitive information disclosure, supply chain, improper output handling and excessive agency. Excessive agency in particular is not a bug anyone patches. It is an agent doing something it was allowed to do, which means the inventory and the scope decisions are the control, and they are cheap before launch and expensive after. To be explicit about the boundary: we build and operate this layer inside your product, we are not an AI security auditor, we do not run penetration tests or red-team engagements, and we do not certify anyone. If your security team wants an independent assessment, they should have one, and what we build is what makes that assessment answerable.
- A.
Nine times out of ten the server works and the model will not pick it, which is a different failure and has a different fix. Start with tool count, because it is the most common one and the least suspected. A team ships forty tools that mirror their REST API, and a model choosing among forty overlapping names with vague descriptions picks badly, gets a confusing result, and stops choosing that server for the rest of the conversation. Fewer, sharper tools win, shaped around the jobs a user actually asks for rather than around your endpoints. Then read your descriptions as though a model were the reader, because it is. Most are written for a developer skimming docs: a noun phrase, no statement of when this tool applies, nothing about when it does not, and a parameter schema with optional fields that are effectively required. The description is the ranking surface, and saying when not to call a tool is worth as much as saying when to. Annotations are the next layer and they are usually unset or wrong. A read-only tool marked as read-only gets tried; a write or destructive tool that is not marked as one gets held back by the host or, worse, gets called when it should not have been. After that come the boring operational reasons, and they are boring in a way that hides them: auth that fails in a way the model reads as an empty result rather than as a fix-this error, latency that makes the host give up, an error string with nothing actionable in it, and results returned as a wall of JSON when the task needed something a person could act on in the conversation, which is what MCP Apps exists for. The way to stop guessing at all of this is to test it the way you test anything else. Write the twenty phrasings a real user would use, run them, and measure how often your tool is selected and how often the task completes. That is an eval set, it belongs in CI, and it turns tool metadata from a thing someone rewrites by intuition into something you can change and prove. Two honest limits: no platform publishes how selection is ranked, and none of them give you a funnel, so measure what happens on your side of the call and treat the rest as unobservable.
- A.
List if a person would plausibly connect you on purpose, and treat it as a product surface with a review process rather than a marketing checkbox. The two doors are different. OpenAI opened third-party app submissions on 17 December 2025 with an in-product App Directory in ChatGPT, browsable from the tools menu or at chatgpt.com/apps, and it reviews every submission against published guidelines before it lists. Anthropic has run a connector directory for Claude since 14 July 2025, extended to consumer services in April 2026. Both are curated, which is the part that changes how you build: the reviewer is reading the same metadata the model reads, so the work that makes you selectable is the work that gets you listed. What it asks of you is mostly discipline. A scope you can state in a sentence, because an app that does one job well reviews faster and gets picked more often than one that exposes your whole API. Tool annotations set honestly, so a write or destructive action is declared as one and a read-only tool is declared read-only. An auth flow that fails legibly and asks for the narrowest scopes that do the job, since the agent should be acting as the signed-in user through your existing authorization and holding no privileges of its own. A UI resource for the tasks that need one, which is what MCP Apps standardized on 26 January 2026 as the first official MCP extension, rendered by the host in a sandboxed iframe. And maintenance, because a listing is a live integration and an abandoned one degrades. One rule to internalize before someone on your growth team suggests otherwise: OpenAI’s guidelines explicitly forbid descriptions, titles, tool annotations or other model-readable fields that manipulate how the model selects or uses other apps, or that interfere with fair discovery. Keyword-stuffing a tool description is not a growth tactic here, it is a rejection. The boundaries are worth saying plainly. The platforms decide what lists and how it ranks, they publish neither, and nobody can sell you placement. We build the app, the tools, the auth and the UI layer, and we prepare the submission. We do not control the outcome of a review.
- A.
More of it than teams expect, because the two variables that set the bill and the wait are both decided in the interface. Datadog’s State of AI Engineering 2026, published on 21 April 2026 from production LLM telemetry across thousands of organizations, found token usage per request more than doubling year over year for the median organization and quadrupling for the heaviest users. That is not people asking longer questions. It is context: history replayed on every turn, whole documents pasted in where a retrieved section would do, tool results appended and never pruned, and a system prompt that grew every time somebody fixed a behavior by adding a sentence to it. Each of those is a Frontend or product decision that shows up on an invoice and, more importantly, in a wait. Four levers, roughly in the order they pay off. What you send: a turn that carries a summarized history and a retrieved slice rather than the entire thread costs a fraction of one that carries everything, and usually answers better, because the model is not reading around the irrelevant parts. What you cache: a stable system prompt and stable context ahead of the variable part is the difference between paying for the same preamble on every keystroke and paying for it once, and it is an ordering decision in your request. What you route: not every call needs your best model, and the classify-then-answer split, a small fast model for the routine path and the expensive one for the hard path, is a product decision about which tasks deserve the wait. And what you render: streaming changes perceived latency more than any model swap will, optimistic and skeleton states cover the first seconds honestly, and a feature that renders progress in the shape of the eventual answer feels finished long before it is. The instrument that makes this manageable is a per-session budget you actually look at, tokens and cost and p95 time to first token for the sessions your users have, not an average across a load test. What we will not do is quote you a number for your product. Cost per session depends on your context strategy, your model choice, your traffic shape and your provider’s pricing, and anyone giving you a figure before they have seen those is guessing. We measure yours in the build and then design against it.
- A.
You instrument the shapes of failure specific to this kind of feature, because your existing monitoring is blind to all of them by construction. A truncated stream is a 200. A refusal is a 200. A wrong answer delivered confidently is a 200 with a good latency number attached. Meanwhile Datadog’s 2026 telemetry has roughly 5% of production model requests failing outright, nearly 60% of that from capacity limits, so the real error rate is both higher than your dashboard says and concentrated in a cause that has nothing to do with your code. Five signals cover most of it. Time to first token, at p95 rather than average, because the average hides exactly the sessions people abandon. Completion rate, meaning the share of streams that finished rather than the share of requests that returned. Degraded-session share, which is every session that hit a retry, a failover to another model, a truncation or a queue, expressed as a percentage of sessions rather than a count in a log, because that single number is the honest health of the feature. Abandonment, which on an AI surface is the strongest quality signal you have and the one nobody wires up: a user who stops the stream, retypes, or closes the panel told you something no eval will. And the outcome the feature exists to produce, the copied answer, the accepted suggestion, the completed action, tied back to the model and the prompt version that produced it, so a regression is attributable rather than merely visible. Two boundaries worth stating. Evals and production monitoring answer different questions and neither substitutes for the other: an eval suite in CI catches a quality regression before you ship, and a rate limit at 9am Monday is not something any eval will ever tell you about. And we build this into your product with the tooling you already run, your tracing, your error tracking, your analytics. We are not an observability vendor, we do not resell one, and we do not sell an SLA on a model we do not operate.
- A.
Start from what the local path is genuinely good at, because that list is shorter and more useful than the marketing version. On-device inference wins on three axes and loses on the rest. Latency, because there is no network in the loop, which matters enormously for anything that should feel like part of the interface rather than like a request: classification as someone types, extraction from a pasted block, a rewrite on a selection, a suggested tag, a completion that is not a round trip. Privacy, because the content genuinely does not leave the machine, which is often the difference between a feature your enterprise customers switch on and one their security team blocks. And unit cost, because you stop paying per token for the high-frequency work that would otherwise dominate the bill, which is frequently the reason a feature like this never shipped at all. What it loses on is capability and consistency. A small on-device model is not your flagship reasoning feature, its context window is a fraction of what you are used to, and it will not produce the same output as a frontier model given the same prompt, so anything where the answer is the product stays hosted. A test that holds up in practice: if a wrong answer is an annoyance the user corrects in a second, local is a candidate. If a wrong answer is the feature failing, it is not. One case deserves naming on its own, because it changes an architecture rather than a line item. A local pass that strips identifiers before anything goes to a hosted model turns "we send your document to a third party" into "we send a redacted version of it", and that is a Frontend capability now rather than a backend project. On cost, both paths are real and we say so instead of pretending the local one is free. The engineering cost is the second path, which is why the shared contract matters so much. The runtime cost moves off your invoice and onto the user’s battery and thermal headroom, on a device you do not control and cannot profile. So it gets measured like any other interaction rather than as a model metric: Interaction to Next Paint on the interaction that triggers it, taken from real devices in the field, reported on the same release-health surface as the rest of the product. A first run that includes a model download is its own measurement and its own designed state, not an outlier to average away.
- A.
You build two paths, not two features, and holding that distinction is the entire engineering problem. Treat the availability situation as structural rather than temporary, because it is. Chrome 148 shipped the Prompt API stable on 5 May 2026, and Mozilla, Apple’s WebKit team, the W3C Technical Architecture Group and Microsoft all objected on the way there, with the TAG review closing without consensus and Edge declining to enable it despite being built on Chromium. Firefox and Safari do not have it. Even within a supported Chrome the answer is per device, because the model is a large local download gated on disk and hardware. So a product designed around the local path being present is a product most of its users experience as broken, and the two-path design is not a hedge, it is the only correct shape. What makes it one feature is the contract. The feature declares what it needs, a typed input and a typed, streamable, schema-constrained output, and that shape is identical whichever path serves it, which is genuinely achievable now that the Prompt API supports output constrained to a JSON schema and your hosted provider has supported the same thing for years. Capability is detected per feature at call time and never inferred from a user-agent string, because availability depends on the device rather than on the browser name. The hosted path is the default and the local one is an upgrade, so the fallback is the well-tested path instead of the one nobody exercises. And the states that exist only on this axis get designed: a model still downloading is a real state with real copy, a device that will never support it quietly uses the other path with no apology rendered to anyone, and a switch between paths mid-session does not change the shape of what the component draws. Two rules we hold throughout. The privacy claim is bound to the path that actually ran, because "this stays on your device" is true locally and false on the fallback, and rendering it on the wrong one is worse than never claiming it at all. And there is no browser sniffing anywhere in the implementation: this roster moves quarterly, and both Mozilla and Apple are pursuing browser AI on their own terms rather than adopting this API, so anything hard-coded against today’s support matrix is wrong by the next release. Feature detection is not a style preference here. It is the only thing that stays correct.
- A.
Everything that depends on knowing what your product is, which is most of it. Be precise about what the edge gives you, because it is genuinely valuable and genuinely narrow. Web Bot Auth lets an agent sign its requests with HTTP Message Signatures, RFC 9421, using a per-agent key, and name its published key directory in a Signature-Agent header. Your CDN fetches that directory, verifies the signature against the key, checks the nonce and expiry, and hands your origin a verified operator identity. Cloudflare, AWS, Akamai, HUMAN and Vercel do this in production today, and Google publishes a directory and implementation guidance for its own agents as an experiment while stating that it does not replace IP and DNS verification and that not every request is signed. That is a real primitive and it removes an entire class of guesswork. What it decides is one thing, per request, in a vocabulary of allow, rate-limit, challenge or block. Now list the questions your product actually has to answer, and notice that not one of them can be answered by a signature. Which parts of your catalogue, pricing, availability or documentation should a verified retrieval agent see, and which are for signed-in humans only. Which of your capabilities should be callable as tools rather than scraped from a rendered page, and with which parameters. What happens when an agent is acting on behalf of one of your users rather than crawling: whose permissions apply, how is that delegation established, and is it recorded in a way you can answer for later. What a caller you cannot verify gets, which for the foreseeable future is most of them. What an operator is allowed to spend, in requests, in inventory held, in anything with a cost attached. And what you serve when an agent asks for something that exists but that this operator should not have. Every one of those is a statement about your domain, your permissions model and your product surface, and it lives in the application because there is nowhere else it can live. That is the work: capability declared as tools over WebMCP or an MCP endpoint, the product truth an agent needs rendered on the server so it does not depend on executing your bundle, authorisation mapped from verified identity to what your model already knows about permissions, limits scoped per operator instead of per IP, confirmation in front of anything irreversible with the real parameters shown, and agent sessions measured as their own funnel with retrieval, representation and action separated. Two boundaries. We build in your product, alongside whatever your CDN already does, and we do not ask you to move or replace it. And we are not a bot management vendor: we do not sell or operate a WAF, a CDN or a detection service, and we do not claim to tell you whether an unsigned request is a person.
- A.
Tiers rather than a switch, and the tier that decides the most is the one for callers you cannot verify, because that is where nearly all of the traffic still is. Start there. A blanket block on unsigned automated requests is the most tempting and most expensive setting available to you, because the systems that decide whether your product is mentioned when a buyer asks a question are largely still unsigned, and a product that cannot be retrieved is a product that is not in the answer. So the default for an unverified caller is not a wall: it is your public product truth, server-rendered, complete and honest, at a rate limit, with no privileged capability and nothing that costs you money to serve. If you do refuse, refuse legibly with a real status code and a machine-readable reason, because a silent block reads to the agent as an outage and to the model behind it as a product that does not work. Verified and known operator is the next tier up, and what it buys is trust rather than access: higher limits because you know who to talk to if they misbehave, structured responses instead of scraped ones, and your declared tools available to call with schemas that say what each one does and which are destructive. This tier is about the operator, not about a user, so it should never see anything a signed-out human could not see. Acting on behalf of one of your users is a different tier and a different mechanism, and conflating the two is the mistake with the worst blast radius. A signature proves which operator sent the request. It proves nothing about whose data they may touch, so delegated access rides on your existing authorisation, scoped to that user, never broader than what the user themselves has, established through a consent step the user actually saw, revocable, and recorded so you can answer afterwards what was done in their name. Anything irreversible sits behind an explicit confirmation that renders the real parameters, the amount, the recipient, the item, because an agent that misread a page and a user who did not look are the same failure. Then the tier nobody plans for and everybody eventually meets: a verified operator behaving badly. Verification is an identity primitive, not a behaviour guarantee, so per-operator limits, spend caps and a kill switch scoped to an operator are part of shipping this rather than an incident response you improvise later. Two honest limits, and they matter more than the tiers. This is early: the IETF working group had adopted no documents as of August 2026 even though several large providers verify signatures in production, so the design has to stay correct when the roster and the details move, which means the verified identity is an input to your authorisation layer rather than a shape your product is built around. And we build this layer with you, in your product, on top of your own authentication and permissions. We are not a bot management vendor, we do not operate a CDN or a WAF, and we do not promise behaviour a standard has not shipped.
- A.
It is a commercial decision made flow by flow, and treating it as one switch is the mistake that produces both of the bad outcomes. Take the case for doing it seriously, because it is stronger than it was a year ago and it is measurable. Agents are now attempting exactly the work your product exists to do. ClawBench, published in April 2026 by researchers at TIGER-AI-Lab, is built from 153 everyday tasks across 144 live websites weighted towards state-changing actions, buying, booking, applying, filling in long forms, precisely because that is what people are now asking agents to do on their behalf. Those attempts land on somebody’s product, and a flow an agent cannot complete is revenue that goes to a competitor whose flow it could, without anybody filing a bug, because the user simply sees a task that did not work. Now the case for restraint, which is just as real. Some flows should not be agent-operable, and saying so is a product position rather than a hedge. Anything where the user’s presence is the point, an irreversible or high-value commitment, anything with a regulatory duty to establish that a person understood something, anything priced on the assumption a human is doing it at human speed. So the deliverable is a tiering of your own flows, and it is short. The first tier is retrieval, which almost always says yes: your public product truth, server-rendered, complete and honest, because the systems deciding whether you get mentioned when a buyer asks a question are largely automated and mostly unsigned. The second tier is capability, the things you want an agent to be able to do, declared as callable tools with schemas and honest annotations over WebMCP in the page or an MCP endpoint beside it, which is a far better answer than hoping an agent drives your UI correctly. The third tier is delegated action, where an agent acts for one of your users, which rides on your existing authorisation scoped to that user, established through consent they actually saw, revocable and recorded. And the fourth tier is the explicit no, which is a decision you make once, write down, and enforce in the product rather than leaving to the shape of your markup. Two boundaries. We build the declared paths, the tools, the authorisation mapping and the interface work. We do not build CAPTCHA solving, bot-detection evasion, or anything designed to make an agent look like a person, because the answer for a legitimate agent is a sanctioned path and a verified identity rather than a hole in your defences, and the alternative would put us on the wrong side of everyone’s terms including yours. And we are not a bot management vendor: enforcement of who gets in belongs at your edge, alongside what we build in the product.
- A.
Less than a rebuild and more than a meta tag, and the honest starting point is that the interface is only part of the gap. ClawBench found the strongest frontier agent it evaluated finishing 33.3% of live web tasks, roughly one in three, while the same class of agent scores in the 65 to 75% range on the older benchmarks built from hosted replicas and static traces. Some of that difference is the agent, and the benchmark says so: long multi-step work still defeats these systems on their own merits. But a large part of it is everything the replica left out, and that part is yours. The failures cluster into shapes any Frontend engineer will recognise the moment they are named. Something appears after the surface was already interactive, a consent banner, a promotion, a session-expiry modal, and the flow the agent had planned no longer matches the page in front of it. A control exists only as a pixel, reachable by hover or by a click handler on a div with no name, so an agent looking at the accessibility tree does not know it is there. A state change is painted but never announced, so the agent cannot tell whether its own last action worked and either repeats it or gives up. A form runs across five steps, and step four silently discards what step two collected. Validation says something is wrong without saying what or where. And at the end, an action either happens twice or reports nothing, because there is no idempotency and no confirmation of what was actually done. The work follows the list, and most of it is unglamorous. Interaction targets get real semantics, accessible names and stable identity, which is the same work the accessibility gate already asks for, so it pays twice: an agent reads what a screen reader reads. Interruptions get resolved before the surface claims to be ready, and anything that has to appear mid-flow is dismissible, focus-managed and does not destroy state behind it. Multi-step flows keep their state server-side and addressable, so a step can be re-entered rather than restarted. Errors are attached to the field they belong to and are machine-readable as well as visible. Anything irreversible renders its real parameters behind an explicit confirmation, and carries an idempotency key so a retry does not become a second order. And for the flows that matter most, the durable answer is not to make the UI drivable at all: declare the capability as a tool over WebMCP or an MCP endpoint, so the agent calls the thing instead of impersonating a cursor. Measure it the way the benchmark does rather than by whether the page looks fine: did the intended state change actually happen, per flow, for agent sessions instrumented as their own funnel across retrieval, representation and action. Three limits stated plainly. This raises how often an agent succeeds, it does not guarantee it, and no interface change compensates for an agent that misunderstood the task. Every one of these fixes has to leave the human experience the same or better, and if a change trades away human usability for machine legibility we have built the wrong thing. And we do not build CAPTCHA solving or bot-detection evasion of any kind: where a challenge is deliberate, the answer is a sanctioned path for callers you have chosen to serve, not a way around your own defences.
- A.
It will keep happening, so the goal is not to avoid it but to make it cheap, and the expensive part is not the part with a date on it. Take the cadence first, because it is now published and predictable rather than a surprise. Anthropic commits to at least 60 days of notice before retiring a publicly released model and its 2026 record runs to about that: Sonnet 4 and Opus 4 were notified on 14 April 2026 and retired on 15 June, Opus 4.1 was notified on 5 June and retired on 5 August. OpenAI’s April 2026 notice covered more than 25 model IDs across two hard shutdown dates, 23 July and 23 October 2026, the October sweep taking GPT-3.5 Turbo, GPT-4, GPT-4 Turbo, o1, o1-pro, o3-mini and o4-mini together with fine-tunes built on them, and the Assistants API itself was sunset on 26 August 2026, a year after the notice. Read as a planning input rather than as news, that is a swap roughly every two quarters for anything long-lived. Now the part that actually costs money. The retirement date is the easy half, because after it the calls fail loudly and you find out immediately. The damage comes from the swap you do voluntarily, on your own schedule, where you repoint at a newer model and the endpoint keeps returning 200 while the behaviour underneath moves: tool-call formatting, adherence to your JSON schema, verbosity, the latency distribution, and where the refusal boundary sits. Nothing errors. Your logs look identical. And the reason this lands on us rather than on your backend team is that almost every consequence is rendered. A component that parses one response shape renders an empty panel when a field arrives named differently. A streaming UI tuned to one token cadence stutters or finishes before its own skeleton does. A card sized for three sentences overflows at eight. A refusal that never previously happened has no designed state, so it surfaces as a blank area or a raw error string. A p95 that moved by a few hundred milliseconds makes the "still working" copy appear at the wrong moment. Prompts are part of it too: yours were tuned against the old model’s quirks, and carrying them across unchanged is where most silent regression comes from. What we build so the next swap is a Tuesday. The model is configuration rather than a literal, set per surface, so you can move one feature at a time instead of the whole product at once. Every response carries the model and prompt version into your telemetry, so "since when" is answerable without archaeology. A regression set is assembled from real production traffic with recorded good outputs, and the candidate is run against exactly those cases and diffed on the things your interface actually depends on, response shape, length, latency, refusal rate and the outcome the feature exists to produce, rather than on a spot check that looks fine. The boundary validates the response and renders a designed degraded state when it does not conform, instead of trusting the shape. A share of live traffic runs the candidate in shadow or canary before the switch, compared on that same outcome. And the rollback is a configuration change, not a deploy. Keep it apart from its neighbours: production health is whether the feature is healthy right now, guardrails are whether an answer is trustworthy, and this is version lifecycle, what changes when the thing underneath you is replaced. Two honest limits. An eval set makes a swap decidable, it does not make it risk-free, and a genuine capability change can still require product work no amount of testing removes. And we build the swap surface and the regression suite inside your product: we are not an evals vendor or a model-ops platform, we do not resell inference, and we do not pick your model for you. That choice stays yours, and the entire point of the work is that it stays cheap to change.
- A.
Pass it this week, then stop looking at it, and spend the real budget on the thing it cannot measure. Start with what changed, because it is a change in measurement rather than in your product. On 17 April 2026 Cloudflare launched a public Agent Readiness Score, a 0 to 100 number anyone can run against any domain at isitagentready.com, added an agent readiness view to its URL Scanner, and began publishing a Cloudflare Radar dataset tracking adoption of agent standards across the internet. Readiness used to be a claim you made in a deck. It is now a measurement a third party takes about you, continuously, without asking, and your buyers and your competitors can take it too. That is genuinely new and it is a reasonable thing to react to. Now be precise about what it reads, because the number is narrower than the name suggests. It checks declarations: robots.txt and a sitemap, Markdown content negotiation, content signals, MCP server cards, an API catalogue, verified agent identity, the agentic commerce protocols. Every one of those is publishable, declarative and mostly mechanical. That is why the correct response is to go and pass it rather than to argue with it, usually in an afternoon or two, and then to hold it true with a CI check rather than with somebody’s memory, because these files rot silently the moment nobody owns them. Treat a passing score as hygiene, in the same category as having a sitemap. It is a floor. What it cannot see is whether an agent can complete anything in your product, and that is where the outcomes live. ClawBench measured that side directly and found the strongest frontier agent it evaluated finishing roughly one live web task in three, against far higher scores on hosted replicas built from static traces. A product can therefore declare everything correctly and still lose every task an agent attempts, which is the worst position of the four available, because a perfect score in front of a checkout an agent cannot finish converts a problem you might have investigated into a false negative you now trust. So the work we actually do, once the declarations are true, is the part with revenue attached: deciding flow by flow what is agent-operable and what is deliberately not, declaring capability as callable tools over WebMCP or an MCP endpoint with honest annotations rather than hoping an agent drives your interface, mapping delegated action onto the authorisation and consent you already have, and instrumenting agent sessions as their own funnel across retrieval, representation and action so you can see where they stop rather than inferring it from a scanner. Three boundaries, and the first is the one that matters most in this conversation. We do not control that score, nobody sells placement in it, and any agency offering to move a third party’s number for you is selling something it cannot deliver. We build in your product, while enforcement of which callers get in belongs at your edge, so we are not a CDN and not a bot management vendor. And we do run our own AgentReady Site Scan, which we offer as a second read on the declarations because that is cheap and occasionally catches something, never as evidence that an agent can use your product. Those are two different claims and we will not let them blur, including when the one we own is the flattering one.
- A.
You stop trying to grade the answer and start recording what the user did with it, which is observable, cheap and much closer to the thing you care about. The instinct is to score correctness, and on most product features there is nothing to score against: there is no reference summary, no correct draft, no single right set of search results. But there is always a user who then did something, and that something is a strong signal. Did they accept the output untouched. Did they accept it after editing, and how much did they change. Did they ask the same thing again in different words, which is the clearest tell that the first answer failed without anyone reporting it. Did they undo. Did they abandon the feature and do the job by hand, which is the comparison that actually matters, because the feature never competed against nothing, it competed against the way the work is done today. Underneath those sits one job-level outcome the feature exists to move, chosen before the build rather than after the dashboard disappoints, and every one of those numbers is read against the model and prompt version behind it, so a change in the result can be traced to a change in the system rather than argued about. Two design decisions make those signals trustworthy rather than decorative, and both are interface decisions. Editing has to be in place and primary, because if the only affordances are accept and discard then everyone who would have made a small correction discards instead, and you have destroyed the exact signal you were trying to collect. And the states have to be distinguishable in the instrumentation: an answer nobody looked at, an answer read and rejected, and an answer read and used are three different outcomes that a naive click event records identically. Now the honest limits, because this is the part that is usually skipped. Every one of these is a proxy. A user who accepts an answer may not have checked it, which means acceptance rises when the interface makes checking hard, so acceptance is always read beside a correction path that people demonstrably use. Thumbs up and thumbs down are close to worthless at product scale and we say so rather than shipping them for the look of it: the response rate is tiny and the people who respond are not the people you are worried about. And a model grading its own output is a development instrument, not a product metric, so it stays in the eval suite and never becomes the number you report to a board. We build the feature, the surfaces and the instrumentation inside your product. We are not a growth agency, we are not an analytics vendor, and we do not write your adoption plan.
- A.
No, and keeping them apart is worth a minute because they get conflated in exactly this conversation, and a team that has one usually believes it has both. An eval suite asks whether the system still produces acceptable output on a set of cases you chose, and it answers that before a release, repeatedly, cheaply and under your control. That is genuinely valuable, we build eval suites as part of this work, and nothing here replaces one. But look at what it is made of. The cases are the ones you thought of, the inputs are frozen, the grading is against a standard you wrote down, and the user is absent. So an eval tells you the feature did not get worse, on the intents you anticipated, judged the way you decided to judge. It cannot tell you that the intent people actually arrive with is one you never wrote a case for, which is the single most common finding when the field data first comes back. It cannot tell you that the output is correct and unusable, because it is three paragraphs where the job needed a number, or because it lands in a panel the user has to copy out of by hand. It cannot tell you that people stopped coming back after the second try. And it says nothing about the outcome the feature exists to move. Field measurement is the other instrument and it has the opposite shape: real intents, no reference answer, noisy, slow, and the only place the two useful directions of feedback exist. The first is that the field tells you which cases your eval set is missing, so every retried intent and every heavily edited answer becomes a candidate case, and the suite stops being a snapshot of what you imagined at kickoff. The second is that the eval suite tells you whether a fix you shipped for one of those cases broke three others, which the field will tell you eventually and expensively. Run one without the other and you get a predictable failure. Evals alone give you a feature that scores well and quietly loses its users. Field data alone gives you a number that moves and no safe way to change anything, because every improvement is a live experiment on real customers. While we are drawing lines, three neighbours use overlapping words and answer different questions. Whether a user can see and interrupt an agent mid-run is agent UX. What the interface does when a call is slow, capacity-limited or truncated is the reliability envelope, and that is health rather than value: a feature can be perfectly healthy and useless. What moves when the model underneath is retired or swapped is model lifecycle. This is whether the thing was worth building. We build the eval suite and the field instrumentation inside your product, against the tooling you already run. We are not an evals vendor, we do not sell an observability product, and we do not resell inference.
- A.
An adapter, if you build it in the right order, and most of the work if you do not. The order is the entire answer here, so it is worth being concrete about what belongs where. Underneath, in your own product and in your own language, sits the thing that is genuinely yours and that no standard defines for you: what a cart or an order or a subscription change actually is in your domain, what is in stock and reservable and for how long, what a price is once tax, shipping, discounts, entitlements and contract terms are applied, which changes are reversible and which are not, and what a completed transaction has to record for finance and support to do their jobs afterwards. None of that is protocol work. All of it is the work, and it is where a mature product already has years of accumulated correctness that took real incidents to learn. Above that sits a capability layer that expresses those operations honestly as callable things with declared parameters, honest annotations on the ones that take money or cannot be undone, and an idempotency key on every one of them so that a retried call is not a second purchase. That layer is the same one an MCP endpoint or a WebMCP tool surface is built on, which is why this work does not strand: a product that has it is also the product that can be operated by an assistant, and neither capability was bought twice. Only then, at the top, come the protocol adapters, which translate between that capability layer and whatever ACP, UCP or AP2 currently ask for. An adapter is small precisely because everything hard is below it, and a standard that fades costs you the adapter. Two design points make the difference between an adapter and a rewrite, and both are easy to get wrong under launch pressure. Never let a protocol’s data model become your data model: the moment a mandate object, a partner’s cart identifier or a session shape from one specification leaks into your database or your components, you have coupled your product to somebody else’s roadmap and the migration cost stops being an adapter. And treat authorisation as its own concern rather than as a field on a request. The genuinely new idea across these standards is that the agent presents a scoped, verifiable mandate for a specific purchase rather than acting with a stored credential, and if you model that properly once, as a bounded permission with a limit, an expiry and a record of the consent the human actually gave, then each protocol is a different way of carrying the same fact. Modelled badly, as a special case in a checkout controller, it has to be rebuilt per standard and it is the part where a mistake is expensive. The honest limit: nobody knows which of these wins, the biggest experiment in the category was retired inside six months, and any vendor telling you they know is selling. Build the layer that is true whichever way it goes. We build the product side of this: the domain layer, the capability layer, the adapters, and the surfaces a person sees when an agent hands the decision back to them. We are not a payment provider, we do not become your merchant of record, we do not touch card data or hold funds, and we do not resell a commerce platform.
- A.
Usually yes, and usually not where teams look first, which is the referral itself. Start from what actually happened to that visitor, because it is unlike every other arrival you have designed for. They did not run a search, scan ten results and click one. They had a conversation, they were told something specific about your product, an opinion was formed on their behalf, and they arrived somewhere already mid-decision, frequently at a deeper page than a campaign would ever land on, having skipped every step of the narrative your funnel assumes they walked through. Then they meet a page that opens with what your product is, which they were just told, and asks them to start a process they believe they are halfway through. That is not a traffic quality problem, it is a mismatch between the state the visitor is in and the state the page assumes. Three things fix most of it and all three are Frontend work. First, answer the claim they arrived with rather than restarting the pitch: the page a visitor lands on from an assistant should confirm or correct the specific thing that sent them, which means the surfaces that assistants actually read (your pricing, your capability pages, your comparisons, your documentation) have to be the same surfaces that convert, rather than thin pages that hand off to a form. Second, carry the intent across the boundary where you can. If an assistant assembled a configuration, a plan, a quote or a shortlist, and the handoff gives you any of that as parameters, reconstruct it and show it back rather than making the visitor retype what they already decided. A person who has to rebuild a decision they already made will usually just leave, and this is the single highest-leverage piece of engineering in the whole cluster. Third, and this is the one that quietly costs the most, make sure the truth the assistant read is the truth your page renders. Price, availability, plan limits, what is included, what a tier does not do: an assistant reads whatever you publish and states it with confidence, and when your page then contradicts it you have not merely lost the sale, you have produced the exact experience that makes someone distrust both of you. Keeping those in sync is a rendering and publishing problem, and it is ours. Be honest about measurement, because this is where the category oversells. You cannot see the conversation that preceded the arrival, referrers from assistant surfaces are inconsistent and sometimes absent, and a meaningful share of assistant-influenced visits will arrive looking like direct traffic. So we instrument what is genuinely observable, which is the landing state and what happened next: which surface received it, whether intent came across, whether the visitor was shown something that matched what they believed, and where they stopped. Those are leading indicators and we label them as leading indicators rather than presenting a closed attribution chain that does not currently exist for anyone. And keep the question separate from its neighbours, because the vocabulary collides. Whether an assistant mentions you at all is discoverability. Whether you serve automated callers is access policy. Whether an agent can drive a flow you built for people is operability. This is about a human being who arrived from a machine already believing something, and what the first screen does about it.
- A.
By deciding scope at write time and treating a cross-scope read as a security defect rather than a relevance bug, because the thing that makes this dangerous is that it does not look like a failure. Take the failure mode first, since it drives every design choice after it. When a database query returns another tenant’s row, something visibly wrong appears on screen and somebody files a bug. When a memory written in one person’s session is retrieved in a colleague’s, the model does not present it as a record. It weaves it into a sentence, in the product’s own voice, as helpful context. The output is fluent, plausible and indistinguishable from the feature working correctly, which means it passes review, passes QA, passes the demo, and is discovered by the person it was disclosed to. Any design that relies on someone noticing is already lost. So scope is structural. Every memory carries its scope as part of the record at the moment it is written, not as a filter applied when it is read, because a read-time filter is a thing one code path eventually forgets and a write-time property is not. In practice three scopes cover most products and they should be named separately rather than collapsed: what this user prefers, which is personal and often sensitive; what this workspace or account has established, which is shared deliberately and is the correct home for team conventions; and what the system has learned about the job across everyone, which must be genuinely impersonal and is the one that quietly accumulates other people’s specifics if nobody is watching. That third category is where most leaks originate, because it is the one that sounds safe. Retrieval is then scoped by construction. The query is bounded by the identity of the caller before it reaches the store rather than after, the same way you already scope every other query in the product, and the scope travels with the session rather than being passed as a parameter something can omit. If your product has workspaces, this is the same tenancy boundary you already enforce, and the useful framing for your team is that memory is not a new security surface, it is your existing one extended to a store people forgot to include in the threat model. Two things we build in because they are the only way to know this is holding. Evals that specifically attempt cross-scope retrieval, written as adversarial cases and run in the pipeline, because a correctness test written by an optimist will never find this. And a visible provenance path, so when a memory is used in an answer the product can say which memory and whose, which turns an invisible class of defect into a reportable one. The honest limit is worth stating: nothing here prevents a user from telling the assistant something they should not have, and no scoping model protects against a memory that was correctly stored and is simply wrong. That is what the controls in the next answer are for. We build this inside your product, behind your existing auth and permissions, in your repo. We are not a memory vendor, we do not host your data, and we do not run your data protection programme.
- A.
More surfaces than most implementations touch, and the gap between what teams believe they deleted and what they actually deleted is the compliance risk in this whole area. Start with the principle, because it settles most of the specifics: under GDPR, personal data does not stop being personal data by changing shape. If the value was personal in the row, it is personal in the embedding, in the cache, in the prompt log, in the eval set somebody built from real traffic last quarter, and in the summary the system wrote about the user last month. So an erasure request is a question about every derived copy, and the honest audit is to draw where a user’s words travel in your system and count the stopping points. In a typical AI feature there are six and teams usually remember two. The memory record itself. The vector representation of it, which is the one most often missed, and an embedding of personal data is still personal data even though it is unreadable, so a deleted row beside a surviving vector is not erasure. Any cache or index in front of the store. The request and response logs, which is where the raw text usually lives longest and where nobody looks because it is infrastructure rather than product. Derived artifacts: summaries, profiles, and the eval sets built from production traffic, which are exactly the thing your team was told to build in order to measure the feature honestly and which quietly became a second copy of everyone’s data. And backups, where the correct answer is a documented restore-time policy rather than a promise to rewrite tape, which is what regulators actually expect. Four design choices make this tractable rather than heroic, and all four are cheap at the start and expensive to retrofit. Memory is stored in a form you can inspect and diff, so deletion is verifiable rather than asserted, which matters because a store of opaque vectors cannot demonstrate that anything was removed. Every derived artifact keeps a reference back to the source record, so erasure is a traversal rather than a search. Personal values are redacted at write time on the paths that only need the shape, which lets the analytical record survive while the personal data does not, and that is the single highest-value change most teams can make. And retention is set deliberately per scope, with expiry as the default rather than as a feature, because memory that never expires is both a growing liability and a worse product: an eighteen-month-old preference is a confidently wrong answer with tenure. On the regulatory framing, be careful who sells you urgency. The obligation that binds you today is data protection law, which has applied for years. The EU AI Act’s record-keeping duties for high-risk systems are the ones the Digital Omnibus deferred to December 2027 and August 2028, so anybody pitching you an August 2026 logging deadline for this is quoting a date that moved. Where the two do eventually pull against each other, keeping a record and deleting the person, the resolution is the redaction boundary above rather than a choice between compliance and compliance. We build the deletion path, the provenance and the controls as part of the feature. We do not act as your data protection officer, we do not certify your compliance, and where your obligations are genuinely unsettled we will say so rather than sell you a position on it.
- A.
Everything that moves, which in this feature is everything that matters. Be fair to the scan first, because the number it produces is real and worth having: it walks a static tree at one instant and applies rules that can be decided from that tree, and those rules catch the failures that dominate the web. The WebAIM Million, published on 30 March 2026 across the top million home pages, found detected WCAG 2 failures on 95.9% of them, up from 94.8% and reversing six years of improvement, at 56.1 detected errors per page, a 10.1% increase, with the same six categories leading for the seventh year: low contrast text on 83.9% of pages, missing alternative text on 53.1%, missing form labels on 51%, empty links on 46.3%, empty buttons on 30.6%. Those are machine-findable and they got worse in the year output volume went up, which is its own argument for a gate. But every one of them is a property of a document that is sitting still, and your assistant is not. Five things the scan is structurally unable to report, and we check all five by hand because there is no other way. The stream, first. Tokens arriving into a live region fail in two symmetric ways and the DOM is perfectly valid in both: announce every fragment and the experience is unusable noise, announce nothing and the reply simply never arrives for a person who cannot watch it appear on screen. The working version announces politely rather than assertively so a long answer does not interrupt the user, marks the region so only new text is read instead of the whole response being re-read on every chunk, and batches at sentence boundaries rather than at token boundaries. Second, the wait. A sighted user reads a spinner. A screen reader user gets silence, and eleven seconds of silence is indistinguishable from a broken product, so the working state announces once that the assistant is composing and does not repeat itself into a loop. Third, focus. The response lands somewhere the user’s focus is not, and controls that did not exist when they submitted, stop generating, copy, regenerate, approve this tool call, appear underneath them mid-stream, so the tab order changes while the user is inside it. The tool approval is the sharp case, because it is a decision point that appears without warning and disappears when answered. Fourth, the semantics of what the model produced. A table rendered as aligned characters inside a code block, a chart with no text alternative, a citation as a bare superscript with no accessible name, markdown arriving as literal asterisks because the renderer did not parse that variant: the markup is valid every time and the meaning is gone every time. Fifth, and this is the category error rather than a bug, shipping a voice mode as the accessibility answer. Voice is a modality, not an accommodation. It excludes deaf and hard of hearing users and users with speech disabilities, and it is regularly built as the only comfortable path into the feature, which converts an accessibility story into an accessibility problem. Worth adding one piece of context because it makes the focus failures worse than they look: the 2025 Web Almanac, across 17.2 million sites, found 67% of sites removing the default focus outline, so the affordance this kind of interface depends on most is the one the industry has been deleting for years. What we do instead of a bigger scan is test it the way it fails: a keyboard and a real screen reader against a live response, in the handful of states that actually occur, once per release rather than once ever. Automated checks stay on the components, where they work. Humans check the stream, where they are the only instrument. We build and operate this inside your product. We are not an accessibility auditor, we do not issue conformance statements or a VPAT, and the merge gate that holds your own codebase to EN 301 549 is Factory work rather than part of this build.
- A.
You do not guarantee the output, you constrain what the model is allowed to choose from, and then the guarantee holds over a finite set instead of an infinite one. This is the same move your design system already made inward, pointed outward at a different author, and it is the single decision that separates a generative interface you can support from one you cannot. Concretely: the model never emits markup. It returns a selection from a typed component registry plus props validated against a schema, and anything that fails validation renders a designed fallback rather than being passed through. The hole every team leaves in this is the raw HTML or unparsed markdown escape hatch, added early because it makes the demo work with any model, and it is the hole through which every accessibility guarantee, and incidentally every injection, walks back in. Once the registry is the only surface, each component in it is built accessible once, has a Storybook entry, carries automated checks and gets a manual pass, and the number of things anyone has to verify stops growing with usage. Then the leaks move into the props, which is where teams stop paying attention and where most of the remaining defects live. A model will supply an empty accessible name, a heading level that makes sense locally and breaks the document outline, an alt text that restates the caption word for word, a duplicate id, and a colour pair it chose from a free-form field with no idea what it lands on. So the schema does the work the model cannot: no free-form colour, ever, only tokens whose contrast was decided when the token was defined. No free-form heading level, the component derives it from where it is being rendered. An accessible name is required, and where the model omits it the component supplies a validated fallback rather than rendering nameless. Ids are generated by the component, never by the model. Composition is the next layer and it is easy to miss, because a set of individually correct components in a nonsensical order still produces a broken heading outline and a tab order that jumps around the screen, so ordering and landmark structure belong to the container your team wrote rather than to the response. What stays genuinely irreducible is the language: the model writes the labels, the summaries and the descriptions, and a confidently wrong alternative text is a model output problem that no schema fixes. The mitigations are narrow and worth doing anyway. A component that conveys data ships with the data rather than a description of it, so a chart carries its table. A decorative image cannot be marked decorative by the model. And the accessibility assertions go into the eval set you already run on the feature, which is the only layer in the whole stack that can test generated output at all: render the actual response, assert the resulting tree, fail the eval rather than the build. Two honest limits and we state both before the work starts. This makes the interface usable, it does not make the answer right, and an accessible wrong answer is still a wrong answer. And a registry constrains what the model shows, not what it says, so a model that misreads its own chart will produce a perfectly accessible summary of something that is not true, which is an evals problem rather than an interface one. We build and operate the registry, the schema and the eval assertions inside your product. We are not an accessibility auditor, we do not issue conformance statements or a VPAT, and the merge gate on your codebase belongs to the Factory rather than to this.
- A.
Everything except what most products do, which is fail the request and show a toast. Start from what is actually true at that moment, because the design falls out of it: the user has already invested effort, they did not choose this limit and in a business product they cannot even change it, and they have no idea whether they hit a wall for the next ten minutes or the next eleven days. Answer those three things and the moment becomes navigable. Preserve the work first, before anything else is decided. Whatever they typed, selected, uploaded or configured survives, and it survives somewhere they can come back to rather than in a component that unmounts. This is the same rule as a capacity failure and worth stating in the same breath, because the two moments look identical to the user and are completely different underneath: a rate limit is temporary, it is the provider’s constraint rather than the user’s, and the honest message is that it will work shortly, while an exhausted entitlement is durable, it is a commercial boundary, and telling somebody to try again in a moment when the answer will be the same in four hours is the kind of small dishonesty that costs a renewal. Name whose limit it was, and be specific, because the answers lead to different actions. A personal allocation is a conversation with an admin. A workspace pool is a conversation with whoever burned it. A plan ceiling is a conversation with sales, and only that third one is an upgrade prompt, which is why an upgrade prompt rendered on all three is the most common way this is done badly. Then give a next step that is real rather than decorative. Depending on the product that is a cheaper path that costs a fraction and still does most of the job, a smaller model with the degradation stated honestly rather than swapped in silently, a wait-until time when the window resets, a queued run that completes when the budget refreshes, or a request that reaches the budget holder with the context attached instead of asking the user to go and explain it themselves. It is worth looking at how the best-resourced version of this shipped: GitHub moved every Copilot plan to usage-based billing on 1 June 2026, and its budget controls stop hard with no automatic fallback to a cheaper model. That is defensible in a developer tool, where the person who hits the wall usually set the budget and understands exactly what happened. It is not defensible in a product where they did neither. Two things worth building that teams skip. Warn before the wall rather than at it, at a threshold expressed in work remaining rather than percentage remaining, because nobody can convert eighteen percent into anything actionable. And instrument the limit as a funnel, how often people reach it, what they do next, and whether the feature ever gets opened again afterwards, which is the measure that tells you whether your packaging is working and is read beside the outcome measures rather than instead of them. One honest limit stated up front: none of this makes a limit that is set too low feel generous. If the ceiling is wrong, a well designed wall makes that unmistakable sooner, which is worth knowing and is a legitimate result of doing this properly. We build the surfaces, the states and the instrumentation inside your product. We are not a billing platform, we do not resell inference, we do not set your limits, and we do not price or package your product.
- A.
By rendering the cost in the units of their work rather than the units of your billing system, and by putting it before the action rather than after it. This is a genuinely new Frontend problem and it is worth being precise about why. Under a seat, the user made one decision about money and never thought about it again. Under a meter, they make a decision about money every time they press the button, and unlike every other pricing model in software, the price of the same button varies with the input, sometimes by two orders of magnitude, because an agentic action that reads three documents and one that reads three hundred are the same click. Faced with a cost they cannot predict, people do not economise, they stop, and they stop before they have found out whether the expensive path was worth it. Four moves, in the order they pay off. Denominate in work, not in currency and not in credits. A credit is an abstraction that exists for your billing system, and a user cannot convert it into anything they care about, so the balance is rendered as roughly how much of their actual job remains, drawn from their own recent usage rather than from an average across your customer base. Keep the credit visible for the person who reconciles the invoice, and never make it the primary number. Estimate before the expensive path. Not every action needs this, and putting a confirmation in front of a cheap one trains people to click through everything, which destroys the affordance where it matters. The rule that works is that anything materially more expensive than the ordinary case renders an estimate and an explicit approval, with the parameters that make it expensive visible in the confirmation rather than the intention, which is the same rule an irreversible action already follows in an agent interface. Show the actual cost afterwards too, quietly, because that is how the estimate earns trust over a few weeks and how a user builds their own model of what things cost. Give them a cheaper choice rather than only a slower one. Where the product genuinely supports a smaller model, a narrower scope or a shallower search, exposing that as a choice with an honest description of what they lose converts a wall into a decision, and it is the single most effective thing we have seen for a feature people have started avoiding. Be honest in that description: a smaller model changes latency, formatting, tool-call behaviour and refusal boundaries, which is the same set of things that moves when a model is retired and replaced, and pretending the cheap path is the same product is how you lose the trust you just spent effort earning. And build the second interface, for the person who pays. In a business product the spender and the payer are different people with genuinely different needs: the user needs to know what remains and what to do about it, the administrator needs allocation, per-user and per-team visibility, alerts before a pool empties rather than after, and caps they can set without opening a support ticket. Products consistently ship the first and defer the second, and then the administrator discovers consumption at the invoice, which is the conversation that decides whether the feature survives the renewal. Two honest limits. A meter that is well rendered still cannot make a price acceptable, and if your packaging is wrong this work will make that visible faster rather than fixing it. And we will not quote you a cost per session before the build, because that number is a property of your context strategy and your traffic, and anyone who quotes it up front is guessing. We build the estimation surface, the read-out, the choices and the administrator view inside your product. We are not a billing platform, we do not resell inference, and we do not choose your pricing model or your packaging.
- A.
Everything between the user and that vendor, which is where the feature is actually won or lost, and which nobody sells you because it is not a product. Take the extraction as given and follow one real document through your product. It arrives from a person, not from a pipeline, so it is whatever they had: a phone photograph of a page at an angle, a spreadsheet whose meaning lives in merged cells, a PDF with a password on it, a 400 MB scan of something that was already a fax in 2009. Before your vendor is reached at all, a series of decisions has been made in the browser about what to accept, what to reject, what to compress, what to split and what to tell the person waiting. Those decisions are not configuration, they are your product, and they are made by default when nobody makes them deliberately. Then the answer comes back and the second half starts, which is the half that decides whether anyone believes it. Four things carry it and all four are rendering. The first is a contract before the wait: what will happen to this file, roughly how long, how many pages, whether it is going to be split, stated before the spinner rather than discovered after it. The second is a read receipt, which is the piece almost nobody ships and the one that changes trust the most: a per-page or per-section account of what was actually read, what was skipped and what came back empty, so a user can see that pages 200 to 300 were never in the answer instead of assuming they were. The third is citation as a first-class state rather than a decoration. A citation has to resolve to a place the user can open and look at, the highlight has to land on the right region of the right page, and an answer that cannot cite is rendered as a failure rather than as prose, because a fluent uncited paragraph is indistinguishable from a correct one and that is the entire problem. The fourth is the failure set, designed rather than caught: the encrypted file, the oversized file, the file that is technically a PDF and is really three hundred photographs, each with a named state that preserves what the user did and names the next action. On what we are not, stated plainly because this is a crowded category: we are not a document-AI or OCR vendor, we do not sell an extraction model, we do not benchmark yours against a competitor, and we will happily build this on top of the vendor you already chose. And there is a limit no interface can move: when a page is genuinely unreadable, nothing downstream makes it readable, so the honest product says which pages it could not read and answers on the rest, rather than answering as if it had read everything.
- A.
A truthful account of what is about to happen, rendered at the moment of the decision rather than buried in a policy page, and then the mechanics that make the account true. Take the moment seriously, because it is the only one where the user still has a choice. Once the file is uploaded the question has been answered on their behalf, and every control you offer afterwards is a remedy rather than a decision. So the first thing the surface owes them is specificity about the crossing: which processor receives it, whether it leaves your tenancy, whether it is retained after the answer and for how long, and whether it trains anything, in one line at the drop zone rather than in a paragraph they will not read. The second is a real choice where a real choice exists. Many products genuinely have two paths, a full one and a narrower one that stays inside their own boundary, and turning that into a visible option with an honest description of what is lost is worth more than any amount of reassurance copy. Where there is only one path, say so instead of implying an option. The third is redaction that happens before the crossing rather than after it, which is a Frontend job when the file is being read in the browser anyway: detect the obvious classes, show the user what will be removed on the document itself so they can correct it, and let them mark more. This works well and it is worth being clear about how far it goes, because the honest version is a first pass with the user in the loop rather than a guarantee, and any product that renders it as a guarantee is writing a promise its detection cannot keep. The fourth is the administrator surface, which in a business product is where this actually gets decided: which file types are permitted, which paths are allowed, what is retained, and a record of what crossed, because the person who has to answer for it is never the person who dragged the file in. Two boundaries. What happens to that content after it is stored, how a user views and deletes it and what erasure has to reach, is the memory question and is answered separately on this page, because a file is data at rest the moment it lands. And whatever the document says is untrusted content, not an instruction, which is the injection rule and also lives separately here. We build the ingestion surface, the disclosure, the redaction pass and the administrator view inside your product, against your processors and your policy. We are not a privacy law firm, we do not give legal advice, we do not certify anyone, and we do not choose your data protection posture: your counsel sets it and we make the interface tell the truth about it.
- A.
Fixed price against a defined scope, always. You get the scope, the deliverables and the price before the work starts, and we do not bill hourly. Builds are shipped either by a scoped project team, by senior engineers embedded in your team on a monthly retainer with a six-month minimum, or through a Frontend Delivery Factory already installed on your codebase, which is usually the cheapest route once the factory exists. Agentic-web capability is the standard bar for our engineers rather than a premium tier, so it is priced into the normal engagement and not quoted as an add-on.
- A.
Not the same product, and the answer is easier once you stop thinking of them as products. They are two transports onto the same behaviour, and the whole point of the capability layer is that adding the second one costs almost nothing while skipping the layer makes both expensive forever. The explainer is explicit that WebMCP is designed to complement rather than replace backend-focused protocols like MCP, and that it is not intended for fully autonomous agents where no browser UI is present, so the split is clean. Your MCP server serves the caller with no browser: a coding agent, a backend workflow, an assistant running somewhere else, authenticated as an integration. WebMCP serves the caller inside the session the user is already in, which is the case your server handles worst, because it is where UI disintermediation and authentication replication actually bite. The browser agent is already signed in as that user, already looking at the record in question, and the tool it calls is your own client-side code, so the interface stays in sync instead of going stale behind an action it never saw. Practically, the first step is smaller than most teams expect. WebMCP has a declarative half that synthesizes tools from ordinary annotated HTML forms, so a search, a filter or a create form that already exists can become agent-callable without new JavaScript, and an imperative half, document.modelContext.registerTool with a JSON Schema and an execute callback, plus getTools, executeTool and a toolchange event for surfaces whose capabilities change as the user moves. If your capability layer exists, execute is one line that calls the function your button calls. If it does not, this is the work that finally forces it, which is the honest reason we sequence the layer first. Now the status, plainly, because this is a dated claim and it should be re-checked before anyone repeats it. The specification lives in the W3C Web Machine Learning Community Group rather than on the Standards Track. Chrome opened an origin trial at version 149, and the agent consuming those tools today is the browser’s own. That is a real signal about where the web is going and it is not a reason to bet a roadmap on it, so we build it as an additive layer behind capability detection: the flow works exactly as it does now when the API is absent, the tools appear when it is present, and nothing you ship depends on a trial staying open. We build inside your product on the model and client you already run. We are not a browser vendor, we do not speak for the specification, and we do not promise you a behaviour the standard has not shipped.
- A.
The same things that stop a person, which is the point of doing it this way, plus three that are specific to a caller that is not a person. Start with what does not change. The permission check is not reimplemented for agents, it is the identical check, run on the server, on the same session, so an agent acting for a user can do exactly what that user can do and nothing more. That is the failure that the parallel-path version produces and it is the expensive one: an agent path with its own authentication is a second door into your product that your security review has never seen, and the explainer names authentication replication as a cost of building it that way rather than as a feature. Then the three that are specific. First, a tool call is untrusted input, always, regardless of which agent made it and regardless of how reasonable the arguments look, because the text that produced them may have come from a page, a document or an email your user never read. The explainer’s own guidance is to validate strictly in code and loosely in schema, and that is the right instinct: the schema is a hint to the model, your function is the boundary, and the boundary is where the rule is enforced. Second, exposure is a decision rather than a default you inherit. Tools are visible to the page itself, to same-origin documents in its tree and to built-in browser agents; sharing beyond that is explicit through exposedTo, and an embedded frame only participates when a Permissions Policy allows it. Which flows are callable at all is a commercial decision made flow by flow, and an explicit no is a legitimate answer for anything where the user’s presence is the point. Third, the irreversible ones keep a human in them. An action that spends money, sends something to another person or cannot be undone renders the real parameters for confirmation rather than a summary of intent, carries an idempotency key so a retried call does not do it twice, and lands in the same activity record a support agent can read back. That is not a courtesy we invented, it is the standard’s stated goal: the page is kept in the loop so the user can see and control what happened. Two honest limits and one boundary. This constrains what an agent can do and it does not make the model’s plan correct, so the flows where a wrong-but-permitted action is expensive still need a confirmation rather than a permission. It also does not replace a security review of the underlying capability: a function that was unsafe when a button called it is unsafe when a tool calls it, and we surface those rather than paper over them. And the boundary is the same one we state everywhere else. We build and operate this layer inside your product. We are not a security auditor, we run no penetration tests and we certify nobody.
- A.
From the system that already owns the content, and if the answer is nobody then that is the finding rather than a reason to invent one. This is the question that decides whether freshness work is real or theatre, so take the failure first. A date typed into a spreadsheet next to a document is a second artifact that rots, on the same mechanics as the first one and usually faster, and an interface that renders an unmaintained date is worse than one that renders nothing, because it converts an unknown into a false reassurance the user has no way to check. So the rule is that the interface never invents a date. It reads one, or it says it does not have one. In practice there are three tiers and most corpora have all three. The best case is content in a system with real metadata: your CMS, your policy tool, your ticketing system, your repository. Published date, last modified, version, status, owner. That travels with the chunk through ingestion and comes out the other side attached to the citation, and the only work is not throwing it away, which most pipelines do because embedding a chunk is easier than carrying its provenance. The middle case is content where the source system knows something weaker, a file modified date or a wiki revision. Render exactly that, labelled as what it is, because last edited is not last verified and a user can tell the difference if you let them. The worst case is content with nothing, a PDF somebody uploaded, an export, a scrape. That is the honest one: the interface says the age of this source is unknown, and unknown is a state you can design rather than a gap you paper over. Then the piece that turns this from display into a working loop. Status has to be able to change, and someone has to be able to change it, so a superseded document is marked superseded with a pointer to what replaced it and the interface renders that rather than quietly dropping it, because a document quietly dropped is indistinguishable from one that was never there. The report control on a wrong answer resolves to the specific chunk and its owner and lands as a correction on the source, not as a ticket in a support queue where the corpus never hears about it. And where your governance is stronger, a re-verification interval per class of content, so an expired chunk is either answered with its age shown or excluded, by policy rather than by intuition. Two boundaries, in the same shape as the ones on the rest of this page. We build the ingestion path that preserves this metadata, the states that render it and the correction loop that feeds it back, inside your product and on the retrieval stack you already run. We are not a vector database, a search vendor or a CMS, we do not sell you an index or an embedding model, and we do not become the owner of your content. And no interface makes a corpus current. What it can do is stop your product from presenting the old answer with the same confidence as the right one, which is the failure your users actually experience.
- A.
Whether the thing you are grading against is still true. An eval compares an output to an expected answer somebody wrote down, and the expected answer was written on a particular day, about a product that has changed since. When it passes, what you have learned is that the feature still agrees with the day the fixture was written. If your product moved and the fixture did not, green is exactly what a wrong feature looks like. This is not a niche worry, it is what happened to the field’s own measurements. The 2026 work on temporal misalignment in factuality evaluation, When Benchmarks Age, is about precisely this: the benchmarks the whole industry cites are static snapshots, TriviaQA from 2017, BoolQ and Natural Questions from 2019, TruthfulQA from 2022, and a considerable share of their samples have quietly stopped being correct, while the benchmarks keep getting cited as though they had not. If that can happen to public benchmarks under continuous academic scrutiny, it is happening to the forty fixtures your team wrote during a launch push and has not opened since. So an eval set gets the same treatment as the corpus, and it is four changes rather than a rebuild. Every golden answer carries an as-of date and the source it was derived from, so a fixture is traceable to a document rather than to somebody’s memory of one. When that source changes, the fixtures derived from it are flagged, which is a link you have to build at authoring time and cannot reconstruct later. Fixtures carry an expiry, so a case nobody has re-confirmed in a year is reported as unverified rather than counted as a pass, and the number your team reads is how many of the green cases are actually current. And the suite includes cases that are supposed to fail: a question whose only supporting document has been superseded should produce the refusal state, not a fluent answer, and if your eval has no case that asserts a refusal then your eval cannot tell a careful product from a confident one. Keep this separate from two neighbouring things, because teams collapse them and then argue past each other. Whether the feature helped anyone is an outcome question and it has its own answer on this page, measured on your users rather than on fixtures. Whether the answer arrived at all is a reliability question. This one is narrower and it is the one that produces the report you are describing: the pipeline worked, the measurement passed, and the content was old. Two limits worth saying out loud. Dating and expiring fixtures raises the cost of maintaining an eval set, which is real and is the reason most teams do not do it, and it is still cheaper than the alternative you are currently paying. And a green suite of current fixtures is evidence about the cases you thought to write, never a guarantee about the ones you did not, which is why the correction path from a wrong answer back to the source matters more than the suite does. We build the eval harness, the freshness metadata and the states around it inside your product. We do not sell an eval platform and we do not grade your product for you.
- A.
By recording four things per change instead of one, and by deciding early that this lives in your document model rather than in a tooltip. A collaborative editor today stores one author per change, because for twenty years there was one kind of author. An agent breaks that in a specific way: a single change now has a model that produced the text, a person who triggered the run, a configuration somebody else wrote, and a moment of application that may have been a third person clicking apply. Collapse those into one author field and you get the two failures your support team will see. Attribute it to the model and a customer cannot find anybody to ask, since the model did not decide to run. Attribute it to the person who clicked apply and you have quietly told everyone a human wrote a sentence a human did not write, which is the worse of the two and the one that costs trust. So the record carries the agent, the profile or configuration it ran under, the person who triggered it, and the person who applied it, and it carries them at the granularity of the change rather than the document. The document-level version, a badge saying AI was used here, answers nothing anybody actually asks. The questions people ask are about a paragraph. Then it has to survive, which is the part that is genuinely hard and the reason this is an architecture conversation rather than a UI one. Attribution that exists only in the editor session dies at the next reload. It has to travel into your operational transform or CRDT metadata, into version history, into the diff between two versions, into export, and into whatever your customers use for review and sign-off, or you have built a label rather than a record. Retrofitting that into a sync layer that was designed around a single author field is real work, and it is much cheaper decided now than after your first enterprise customer asks which parts of a contract a model wrote. There is evidence about how this gets used, and it changes what you build. The CHI 2026 study of 30 people across 14 teams working in a shared editor with agents for a week found that teams pulled agents into their existing norms of authorship, control and coordination rather than treating them as members of the team, and that the agent configurations people made read as personal territory while the outputs became shared. So attribution is not a compliance ornament, it is the mechanism a team uses to decide whether to trust a paragraph, and it needs to name the colleague behind the agent rather than only the agent. Two boundaries. We build the attribution model, the rendering and the paths it has to survive, inside your product and on the editor and sync stack you already run. We are not an editor vendor, we do not sell you a CRDT or a real-time backend, and we do not become the owner of your customers’ content. And attribution makes accountability answerable, it does not assign it. Who is responsible for a sentence an agent wrote into a customer’s document is settled by your terms and your customer’s own policy, and we will not pretend an interface decides it.
- A.
Propose by default, edit directly only where a team has knowingly turned it on for a specific surface. That is the opposite of what most teams ship first, so here is the reasoning rather than the rule. The strongest available evidence points the same way. In the CHI 2026 study by Lehmann, Shauchenka and Buschek, the prototype that 30 people across 14 teams used for a week of real writing work deliberately put agent responses into the familiar comment feature rather than into the body of the document, and made the agents themselves visible to everyone as shared objects. What the researchers found is that teams absorbed the agents into their existing norms of authorship, control and coordination. Those norms are the thing that makes a shared document work, and they are built entirely on changes being proposed, seen, discussed and accepted by people. An agent that writes straight into the body does not participate in that, it bypasses it, and the cost lands on the co-authors rather than on the person who ran the agent. There is a product argument on top of the research one. A proposal is reviewable, attributable and cheap to reject, and rejection is the common case early in a feature’s life when the agent is not yet good. Direct edits are none of those things: they are expensive to reject because reverting them competes with two other people’s live edits, they blur the authorship record at exactly the moment it matters, and they make the feature feel unsafe long before anybody can articulate why. Teams read that as a quality problem and go tune the model. It is not a quality problem, it is a placement problem, and no amount of model quality fixes it. Where direct editing does earn its place, and it does, the conditions are specific. The change is mechanical and verifiable, like applying a formatting rule or a terminology list. The scope is bounded and visible before it runs. It is reversible as one unit without disturbing anything else. The team turned it on for that surface deliberately, rather than inheriting it as a default. And it is still attributed, because a direct edit is not an anonymous one. Two design decisions get made at the same time and are easy to miss. Where the proposal lives is a real choice, since comments, suggestion mode and a side-by-side diff each teach the user something different about how final the change is, and picking the wrong one is how a feature reads as pushier than it is. And an agent writes faster than a person and never yields, so how much it may propose at once, and in whose region of the document, is a product decision made before launch rather than a rate limit added after the first complaint. We build the proposal surface, the application path and the attribution behind it inside your product. We do not sell you an editor, and we will not ship the direct-edit version as a default because it demos better.
- A.
They point in opposite directions and the test takes one sentence. The Factory changes how your organization ships: it is delivery infrastructure installed on your codebase so people outside the Frontend team can merge production Frontend. Frontend AI changes what your product does for the people and agents using it. If your problem is that good ideas queue behind a small Frontend team, you want the Factory. If your problem is that your product needs to do something it cannot do yet, you want Frontend AI. Teams often arrive through one and add the other later, and a factory already running is the fastest way to ship the second. What we will not do is sell you one while describing the other.
- A.
Their own data, in the place they are already looking, phrased as the next move rather than as a sample. The difference between an example prompt and a starting point is whether the user recognizes the nouns in it, and that difference decides whether the first interaction is a demo or a first task. A static example says here is a thing this can do, in general, to somebody else’s data, and it asks the user to perform a translation into their own situation before they have any reason to invest in the translation. A starting point built from the record on screen, the file just uploaded, the report open in the tab or the last three things they did says here is a thing this can do to that, now, and the click is a decision rather than an exercise. Underneath that sit three moves worth doing in order. Put the entry points at the objects, not at the top of the app. One global field far from the work is a single affordance covering everything, and there is direct evidence that a single affordance is the wrong shape here: Nielsen Norman Group ran a diary study across ChatGPT, Bard and Bing Chat where 18 participants logged 425 conversations, and found six distinct conversation types, ranging from vague exploratory prompting to razor-sharp single questions, concluding that they serve different information needs and call for different interfaces. An action attached to a row, a document, a chart or a selection names its own scope and needs no vocabulary from the user. State the boundary rather than implying it, because a user who cannot tell what the feature can see will either over-ask and get a refusal that reads as a failure, or under-ask and never find the capability that would have sold them. And keep the free-form field, because the specific end of that range is real and the people at it are your best users. Just stop making it the front door. Two things not to do, both of which we have watched teams ship. Do not lead with a capability list, since a list of what a feature can do is a manual, and the CHI evidence on prompt-based tools is that people skip the manual and learn in the box. And do not generate the suggestion from a model on every load without pinning it, because a starting point that changes each time is not a surface anyone learns. We build this inside your product on the stack you run, and we instrument which starting points get taken, which get edited before they run, and which get ignored, because that is the fastest signal you will get about what your feature is actually for.
- A.
They cannot, unless the interface supplies what expertise would otherwise have supplied, which makes this a rendering problem and yours rather than the model’s. The clearest evidence for that is a comparison inside a single study. I Just Need GPT to Refine My Prompts, by Gautam, Bhatia and Chilana of Simon Fraser University, presented at CHI in Barcelona in April 2026, observed 26 people using prompt-based generative tools, 14 casual users and 12 professionals. The professionals brought domain expertise to the output: they refined across iterations and they critically evaluated results, discarding the ones that did not meet their standards. The casual users settled for good enough. Same tool, same model, same prompts, and the variable was who could tell. In a consumer or cross-functional product you do not get to staff the evaluating side, so either the interface does it or good enough is what ships to your customers under your brand. What that requires, in order of how much it moves. Grounds rendered with the answer rather than behind a disclosure, meaning the specific rows, passages, documents or fields it drew from, positioned so a user can check one without leaving the answer. Something to compare against, which is the move most products skip: the previous value, the unedited version, the number the user expected, or two candidate answers side by side, because a judgement is far easier to make against a reference than in the abstract. Uncertainty said in the interface rather than in the prose, since a model that hedges in a sentence still renders as a confident paragraph. Correction as the primary action instead of regeneration, because someone who can fix an answer will keep a feature that is right most of the time, and someone who can only accept or discard will leave. And rejection that costs one click and is recorded, which is both the user’s exit and your most informative event, and it is the one almost every product discards. Two boundaries. None of this makes a wrong answer right: if the underlying answers are wrong, that is a reliability problem and interface work will only make the wrongness legible, which is better but is not a fix. And what happened to the answer after it arrived is measurement, and it is a separate question from this one. This one is about whether the person in front of it had any basis for a decision.
- A.
No, and the research says so more sharply than most teams expect. Counting the Wait, presented at CHI in Barcelona in April 2026, put 425 people through a 10, 30 or 60 second wait with one of three displays: time remaining, time elapsed, or no time display at all. Showing time remaining produced more frustration than showing time elapsed. Showing nothing made the wait feel longer and left people unsure whether anything was happening. So the two options most products actually ship, a bar with an estimate and a spinner with no information, are the two the evidence argues against, and the one that reads as least designed is the one that tested best. The mechanism is not mysterious. A remaining-time display is a promise, and a generative system cannot keep it, because duration depends on the model, the length of the answer, the tool calls it decides to make, and whatever the provider is doing at that moment. So the estimate gets revised, and every revision is a broken promise the user watches happen. A determinate bar that stalls at 80% is worse than no bar, and a bar that jumps from 30% to done teaches people the number was never real. Once that is learned it is learned for the whole product. What we build instead has three parts. Elapsed time, plain, counting up, because it is always true and it never has to be corrected. The name of the step that is actually running, in the user’s vocabulary and not your architecture’s, so reading the sources and drafting the summary rather than invoking tool 2 of 4. And evidence of work wherever the work produces any: the documents it found, the rows it is reading, the outline before the prose. A step that names something the user recognizes does the job the percentage was pretending to do, which is to answer the question the user is actually asking, which is not how long but is this working. Determinate progress stays available for the one case where it is honest, which is a bounded queue you control, forty files being processed and eleven done, and even then it counts units rather than time. Two things not to do. Do not animate a fake bar to a plausible position, because it is a lie with a short half-life and your support queue learns it before your PM does. And do not collapse a long wait into an optimistic UI that shows the result before it exists, which is defensible for a reversible local change and indefensible for anything that spends money, sends something or cannot be undone. We build this inside your product on the stack you already run. One honest limit that the paper states and we repeat: in a short, repetitive task the choice of display changed how the wait felt without changing how people performed afterwards, so the return on this is abandonment and trust rather than measurable throughput, and we would rather say that than sell you a number.
- A.
No, and once a wait is that long the mistake is treating it as a wait at all. Roughly ten seconds is the boundary where a person stops attending to a screen and starts doing something else, which is decades-old human-computer interaction and has not been repealed by the fact that the thing on the other end is a model. Past it you are no longer designing a loading state. You are designing a job, and a job has properties a spinner does not have. It exists after the tab closes. It has a result that lands somewhere findable rather than only in the component that started it. It can be cancelled in a way that stops the work and the spend, not just the animation, which is the one most products get wrong because cancel is wired to the rendering and the tokens keep being paid for. It tells the person when it is done, through whatever channel they already watch, and the notification opens the result rather than the page that started it. It survives a reload, and it survives two tabs, which means the state lives on the server and the client subscribes rather than the client owning it. And it is idempotent enough that a refresh does not start a second one, which is the failure that turns a slow feature into a doubled bill. The interface work sits on top of that. The action that starts it says what will happen and roughly how long the class of job takes, in a range and from your own telemetry rather than as a per-run estimate. The job is visible while it runs without holding the user in place, so a small persistent indicator with elapsed time and the current step, reachable from anywhere in the product. Partial results appear as they become usable rather than being held back for a single reveal, but only where a fragment is genuinely usable: half a paragraph is, half a price is not. Failure is specific and resumable, which means it says which step failed and offers a retry that starts from there rather than from zero, because a two minute job that fails at ninety seconds and restarts from the beginning is the moment people stop using the feature. And the cost of a run is visible before it starts if the user is the one paying for it. Two boundaries. This is not the same as an agent run a person supervises step by step, which is its own answer above and is about visibility and intervention inside a sequence the user is watching. This is one request that got long, and the design question is whether the user is allowed to leave. And none of it makes a two minute job into a two second one. If the duration itself is the problem, that is a model, retrieval and architecture question, and it is the one we answer when we look at what the feature costs to run.
- A.
Imperfectly, from behaviour rather than identity, and the honest answer to the second half is less than teams expect, because most of what you should do is worth doing whether you detect anything or not. Take the detection question seriously first, and start by accepting what it cannot be. There is no header to trust, no signature to verify and no operator directory to fetch, because the request is your user’s: their cookie, their device, their session, issued by your own login to a person who is entitled to it. The signature and verified-operator machinery that answers the question for a caller arriving from outside your product has nothing to attach to here, and pretending otherwise is how teams end up blocking customers. What is actually available is behavioural, in-session, and probabilistic. Interaction that arrives without the motion that normally precedes it, a field populated in one atomic write rather than as keystrokes, navigation faster than the previous view could have been read, a sequence that is correct but takes a path no human path-of-least-resistance would take, perfect form completion on the first attempt across flows where humans have a measurable error rate, tab and focus patterns that do not look like a person switching. Each of those is weak alone and the combination is a probability, never a fact. So the rule we enforce in the design is that the signal may never be load bearing: it may inform what you log, what you measure and where you offer a better path, and it may never be the thing that refuses to serve somebody, because your false positives are your most capable customers using an assistive tool or a keyboard or a password manager. Now what changes when the probability is high, and it is three things, all of them cheap. The session gets an actor, which is a small schema change with a long tail of value: an event carries the account, plus the fact that it was likely agent driven, and that flows into your analytics, your fraud rules, your support tooling and the account activity view your customer can read. Nobody can answer what was done in this account and on whose instruction if the only field you kept was the user id. Second, the product offers a better road rather than a worse one. If a flow is being driven by an agent repeatedly, that flow is a candidate to be declared as a callable tool over an MCP endpoint or WebMCP in the page, which we cover separately, and the offer is a plain one: the agent gets a described interface that will not break next release, and you get authentication, rate limits, parameters you validate and a record. Detection that only ever produces friction teaches agent makers to hide from you; detection that produces a sanctioned path teaches them to identify themselves, which is the outcome you actually want. Third, the irreversible steps get their confirmation tightened, and that is a control you should already have. Two boundaries. We build this inside your product, on your own session, analytics and authorisation layers. We are not a bot management vendor, we do not sell or operate a detection service, a WAF or a CDN, and we will not tell you that a score is a certainty. And we do not build fingerprinting that follows a person across properties to answer this question, because the question is about one session in your product and the answer does not need a profile.
- A.
You can, and you should price it honestly first, because the bill is larger and lands in a stranger place than the policy conversation suggests. Three costs, in ascending order of how much they hurt. The first is that you cannot do it accurately, which the answer above covers: the traffic is your own authenticated user’s session, the signal is behavioural, and every enforcement action you take is taken on a probability against somebody who is paying you. A block that is right nine times out of ten is a block that throws out a real customer every tenth time, silently, in a flow they will not report as a bug because it looked like the product being broken. The second cost is the mechanism. The tools that reliably stop an agent are the ones that stop it at the point where it has to prove it is a person: challenges, interstitials, a step-up that requires reading an image or holding a phone. Those work, and there is a measurement of how well: Web Bench, an open browser-agent benchmark of roughly 2,450 tasks across 452 live sites drawn from the global top thousand by traffic, found that the write half of the web, authentication, form filling, second-factor prompts and file operations, is where agents fail far more than the read half, and that a login wall or a challenge often stops an agent before it does anything at all. That is the good news for a blocking strategy and it is immediately the bad news, because those same mechanisms are the ones that fail screen readers, switch access, voice control, low-vision zoom and every user on a slow device, and in the European market that is not only a conversion problem, since the accessibility obligations we cover elsewhere do not carve out the paths you added to stop robots. You would be shipping an accessibility regression and a conversion loss in order to answer a policy question, and the people it lands on hardest did not send an agent anywhere. The third cost is strategic and it is the one worth dwelling on, because August 2026 moved it. The Ninth Circuit vacated the injunction in Amazon.com Services, LLC v. Perplexity AI, Inc. on the reasoning that the user directing the agent is the one accessing the site, which means the class of traffic you are considering blocking is, increasingly, your own customer choosing how to use your product. The court left contract and other theories open, so your terms are still yours to write, and this is exactly why it is a product decision rather than a legal one. A competitor whose flows complete under an agent will finish the task your flow refused, and neither you nor the customer will see a bug report. So the position we build toward is narrower than a block and it holds up better. Decide the no list by consequence, flow by flow, and make it short: the places where a person’s presence is the point, an irreversible commitment, a regulatory duty to establish that somebody understood something, anything priced on the assumption of human speed. Enforce those with a confirmation that renders the real parameters and requires a person, which is a control that works regardless of what you detected. Leave the rest open, declared as tools where the traffic justifies it, rate-limited per account and recorded with an actor. And where you do refuse, refuse legibly, with a real status code and a machine-readable reason, because a silent block reads to the agent as an outage and to the model behind it as a product that does not work. Two boundaries, the same ones we state everywhere. We are engineers and not lawyers: your terms are your counsel’s call. And enforcement of who gets in at the edge belongs to whatever you already run there, not to us.
- A.
By making the capability a policy your product evaluates rather than a build you ship, which is one layer of work if it is done before the second customer asks and a migration if it is done after. The instinct teams have first is the one to name and discard: a build flag, a separate deployment, or an environment variable per large customer. That is two products within a quarter and four within a year, and the tell is always the same, a bug that reproduces for one customer and not another because the branches drifted. The version that holds is a single code path with a resolved policy in front of it. Three properties decide whether it survives contact with procurement. It is server-side, because a flag read in the client is a suggestion: the customer’s security team will check whether the request still reaches the provider when the toggle is off, and in most first implementations it does, since the switch was wired to the button rather than to the call. It is resolved once per request at a known layer and passed down, rather than each feature reading the setting itself, because the second pattern is how one surface gets missed and a disabled feature answers anyway in an email digest or a webhook or an export nobody classified as the AI feature. And it is hierarchical in the way your customers actually organise, which is tenant, then workspace or group, then user, with the tenant able to lock a level below it, because the admin who bought the control wants it to be a control and not a default. Then the granularity question, which is where the real negotiation happens, and the answer is not one switch. Enterprise buyers rarely want the whole feature off. They want inference off for one class of data, or generation allowed and training or retention refused, or the assistant available but with no ability to act, or the feature on for one department during a pilot. So the unit of the policy is a capability rather than a product: this data class may be processed, this action may be taken, this provider may be used, this retention applies. Each of those is a row a salesperson can point at in a security review, and the list of rows becomes the thing you negotiate instead of the roadmap. The Frontend work is the half that gets underestimated and it is most of what the customer actually experiences. An admin surface where the policy is legible, with each control saying what it changes in plain language and what it does not, because a toggle whose effect is ambiguous produces a support ticket per renewal. A product that degrades honestly rather than breaking when a capability is off, which means the entry point is absent or explained rather than present and failing, and no dead affordance that returns an error a user cannot act on. A visible record of who changed a policy and when, since the admin is accountable internally for the setting. And an effective-policy view, because in any hierarchy the question that matters is not what did I set, it is what is actually in force for this user right now, and that is a screen almost nobody builds until the first argument. Two boundaries, the same ones we hold everywhere. We build the control layer and its surfaces inside your product, on your own authorisation and data model. And we are not auditors and not your counsel: what you are obliged to offer and what your contract must say are decisions we build to rather than decisions we make.
- A.
A named human, a bounded action and a record they can read without you, and most logs shipped with an AI feature fail on the first of those three. The usual artifact is an engineering trace: request ids, model names, token counts, latency, written for whoever debugs the feature and retained wherever your observability vendor keeps things. It is genuinely useful and it is not what is being asked for. The question behind the questionnaire is an accountability question, and the reference points buyers cite make that explicit, since Article 12 of the EU AI Act is about record-keeping that supports traceability and Article 14 is about a human being able to oversee and intervene. A trace that identifies a service account answers neither. Six things make the difference, and none of them is exotic. An authenticated person on every entry, or an explicit statement that there was none and which automation acted instead, because the first question after any incident is who told it to do that. The action in your product’s own vocabulary rather than the model’s, since a customer’s security team cannot audit a chat completion and can audit a draft was generated in this document or a refund was proposed on this order. The inputs by reference and by class, not by value, which means naming the records and the data classes that entered the context rather than copying the content into a second store, since a log that duplicates sensitive content is a new liability presented as a control. The outcome, including refusals, which people forget and which is the half that proves the guardrails ran. Whether a human approved it, where approval was required, because that entry is the one that makes the oversight claim checkable. And the provider and model version that processed it, which is what makes a subprocessor change or a model swap auditable afterwards instead of being reconstructed from a changelog. Then the part that decides acceptance, and it is a Frontend deliverable: the customer’s own admin has to be able to read it. A ticket to your support team is not a control, and a security team that has to ask you for evidence has been told the answer to their question is no. So it is a screen in the admin area with filters that match how an investigation actually runs, by person, by date, by action class, by outcome, plus an export in a format their tooling ingests, plus optionally a stream into whatever they already collect, which for a large customer is usually the difference between a control they believe in and a demo. Retention is a setting rather than a constant, because their obligations are not yours. And access to the log is itself scoped and recorded, since a log every employee at your customer can read is a disclosure surface wearing a compliance badge. Two things we say plainly to keep this honest. A complete log is evidence, never a guarantee: it proves what happened, it does not prove the feature behaved well, and we will not let it be sold internally as the latter. And the boundary is the usual one. We design and build the record, the retention and the surfaces inside your product. We are not auditors, we do not certify compliance, we do not write your data processing agreement, and what you are legally required to keep is your counsel’s call.
- A.
By never giving it the ability to drift, which means the model chooses from a registry and is structurally incapable of emitting anything else. The distinction that matters is between constraining the output and validating it afterwards, and almost every generative UI demo does the second. If the model returns markup, or a class string, or a style object, then your design system is a suggestion in a prompt and the only thing standing between your product and an invented button is how well that prompt was written this week. Prompts are not a boundary. A schema is. So the contract looks like this. There is a registry of components the model may use, and it is generated from the code that defines them rather than maintained beside it, because a hand-kept list is out of date the first time someone adds a variant and drift in the description is worse than no description. Each entry carries the typed props, what the component is for, and what it must not be used for, that last one being the field teams leave empty and the one that prevents most misuse. The model returns a structure, not a rendering: component name plus props, validated against the schema on arrival. Anything failing validation does not reach the page. There is a declared fallback for a component the model asked for and you do not have, because it will ask, and the difference between a graceful fallback and a blank region is the difference between a degraded screen and a support ticket. And composition itself is constrained: which components may nest inside which, how many, how deep, because a valid component in an invalid arrangement is the second failure mode and it appears the moment the first one is fixed. Then versioning, which is the question behind the question and the one that bites in year two. The registry is versioned with the design system, so a component whose props change is a breaking change to the interface contract exactly as it is to any other consumer, and the model is a consumer. Renamed or removed components need a mapping, not a deletion, since a model with stale context will keep asking for them. And new components are not automatically available: entering the registry is a deliberate act with a decision about whether this should be assemblable at all, because plenty of components, anything destructive, anything that takes payment, anything carrying legal text, should only ever appear on a screen a human designed. That list is worth writing down early. Three things worth saying plainly. Constraint is not correctness: the model can select a perfectly valid chart and select the wrong one, and no schema catches that, which is why the instrumentation and the fallback to the built UI are part of the design rather than nice-to-haves. The registry is a Frontend artifact, so it is the same discipline as the inward design-system guard but it runs at request time against a machine rather than at merge time against a diff, and the two share a source of truth rather than being separate projects. And we build this inside your product, on your own component library: we are not an accessibility auditor, we do not issue conformance statements or VPATs, and the accessibility of a generated screen is only ever as good as the accessibility of the pieces it was assembled from, which is exactly why it has to be tested there.
- A.
By making the interface reproducible from a record, which is a decision you make before launch or a rewrite you do after the first bad month. Name the problem precisely, because it is not the usual one. The user saw a screen, the screen was assembled for them, and it is gone. Your support agent cannot open the same page. Your engineer cannot reproduce it from a URL. The screenshot the customer sent shows a layout nobody on your team has ever seen and cannot find in any file. Every tool your support organisation has was built on an assumption that just stopped being true, which is that a given route renders the same thing for everyone who is allowed to see it. So the render is recorded, and what is recorded is the structure rather than a picture. For every assembled interface you keep the request that produced it, the resolved component tree with its props, the registry version and the model version in force, and the identifiers of the data the components fetched, by reference rather than by value, since copying the content into a log is how a support tool becomes a second copy of your customers’ data. From that record the same interface can be rendered again, which is the property that makes everything else possible. It gives support a view of what the customer actually saw. It gives engineering a reproduction that is a record rather than a story. It gives you a regression corpus, because real recorded interactions replayed against a new model version or a new registry version will tell you what changed far better than any synthetic evaluation. And it gives you the evidence for the conversation that eventually happens about whether the feature did something it should not have. Three surfaces make it usable. A per-render identifier the user can see and quote, small and copyable, so a support ticket starts with a reference instead of a description of a layout. An internal viewer that replays a render from that identifier with its inputs shown. And the same actor and outcome fields the rest of your product logs, so the assembled screen is not a category of event that lives outside everything else. Retention is a setting with a real answer, since these records accumulate quickly and their value decays fast. Then the part that is organisational rather than technical, and it is the one teams find out the hard way. Your support team needs to know that layouts differ per request, or they will spend the first month telling customers to clear their cache, and your documentation cannot screenshot a screen that varies, so the durable documentation is of the components and the jobs rather than of the pages. Both are reasons the path back to the built UI matters: when someone needs to be walked through a task over the phone, the deterministic screen is the one you walk them through. Two limits. A replay reproduces the interface, not the model’s reasoning, and we will not present it as an explanation of why the model chose what it chose. And this is a product surface we build inside your application on your own data model; we are not an observability vendor, we do not join your on-call rotation, and none of this makes a generated interface correct, only accountable.
- A.
By making the configuration data rather than code, which sounds obvious and is exactly what nobody does, because the first customer gets served with a branch and the second one gets served with a copy of it. Say the rule out loud before the first deal closes: one code path, many declared configurations, no forks. Everything below is how that holds. Each configuration carries a capability descriptor, and it is the centre of the design. Does this endpoint stream, does it accept images, does it return structured output reliably, does it call tools, what context length can you actually count on, what is its real concurrency. Your feature reads that descriptor instead of assuming, and every branch in the interface that depends on a capability reads it from there rather than from a build-time constant. The descriptor is not written by hand from the customer’s documentation, because documentation lies about the thing you need: it is produced by a conformance suite you run against their endpoint at configuration time, which is a fixed set of probes that exercise the exact behaviours your product depends on and records what came back. It runs again on a schedule, because the endpoint behind an OpenAI-compatible URL can change under you without anybody telling your customer either. Then degradation is designed once, per capability, not per customer. No streaming means a different progress affordance, not a broken one. No structured output means a parse-and-repair path with a declared failure mode. No tool calling means the flows that need it are visibly unavailable in that tenant rather than silently missing, because a feature that is absent without explanation is read as a bug in your product. Write each degraded path once and test it against a deliberately reduced endpoint in CI, which is the same discipline as testing your interface at a small viewport and is skipped for the same reason. Then publish tiers, exactly as you publish browser support, because it is the same problem: verified configurations you test in CI and support fully, compatible ones that pass the conformance suite and get best effort, and unsupported ones you decline in writing. An unbounded promise to work with any endpoint is not generosity, it is an open-ended support contract you signed without pricing it, and buyers respect a published tier list far more than a yes that quietly becomes a no. Two more things that keep the fork away. Prompts stay portable, which means no vendor-specific syntax in anything shared, and where a configuration genuinely needs a variant it is an overlay on the common prompt with its own tests rather than a second prompt somebody maintains in parallel. And the golden flows run against every verified configuration on a schedule, so a regression on somebody else’s endpoint reaches you before it reaches their admin. Boundary, and it is the same one we hold everywhere. We build the descriptor, the conformance suite, the degradation paths and the tier discipline inside your product. We do not operate your customer’s cloud, we do not certify their residency or sovereignty posture, we are not your counsel, and we will not recommend which model they should point at.
- A.
Attribution, and it has to be built before the complaint rather than after, because once the conversation has started every number you produce looks like an excuse. Three surfaces, in the order they earn their keep. First, the end user sees what is true. Latency that belongs to their organisation’s endpoint is still latency the user is waiting through, so the interface says so in the plainest available form and offers the one thing that helps, which is a way to leave and be told when it is done. What it must never say is that your product is unavailable, because that sentence is both false and unactionable, and it converts an infrastructure decision the customer made into a defect they attribute to you. Second, the admin sees the mechanism. Their own console shows which provider and model version answered, the latency distribution for their configuration and not a global average, the error and refusal rates, the throttling they are hitting, and the conformance results for their endpoint with anything degraded named explicitly. That last one is usually the whole conversation: a customer reporting the feature is worse is very often a customer whose endpoint quietly fails a capability probe, and showing them that in their own console on the day it happens is a different relationship from discovering it in a support thread in week six. Third, and this is the surface that ends the argument rather than winning it, the admin can run a comparison. The same fixed set of representative tasks against their endpoint and against your reference configuration, with the outputs side by side and the timings attached. It reframes the discussion from your product is bad to this model is slower on this class of task, which is a decision they own and can act on, and it is the only version of this conversation that leaves the relationship intact. One thing to never do, and it is the tempting one. Do not silently fall back to your own model when theirs fails or performs badly. It looks like the helpful engineering choice and it is a data boundary breach wearing a helpful hat: the entire reason that customer configured their own endpoint is that their data must not go to yours, and a fallback you did not declare sends it there at exactly the moment nobody is watching. If a fallback is permitted at all it is a per-tenant setting, off by default, disclosed in the interface when it engages, and written into the activity record. And set expectations at configuration time rather than at incident time. When their endpoint is added, show the conformance result and what it means for their users, in plain language, before they save. A customer who was told at setup that their configuration cannot stream and will feel slower on long answers is a customer running a tradeoff they chose. The same customer told six weeks later is a customer being managed. Two limits we say out loud. We cannot make their model better, and we will not build a layer that pretends to: prompt work and routing within their own endpoint have real headroom, but a smaller model is a smaller model and the honest move is to show it rather than paper over it. And the boundary stands: we build the attribution, the comparison surfaces and the disclosure inside your product, we do not operate their inference, we are not your counsel, and we do not certify anything for either of you.
- A.
In the code paths nobody thinks of as the AI feature, which is why an audit finds them faster than a design session does. Walk the asset from creation to every exit and mark each hop that re-encodes, resizes, converts or rasterises, because every one of those drops a signed manifest unless somebody wrote code to carry it. The usual list, in the order we usually find them. The upload path, where a normalisation step converts to a single format and a privacy step strips EXIF and takes the Content Credential with it, since both are usually one library call with a flag nobody revisited. The image service, where five responsive widths and a modern format are generated on the fly at the CDN edge and the derived files carry nothing, which is the most common single loss point in a React or Next.js product because the transform lives outside the repository. Thumbnails and preview cards. Any canvas work: crop, annotate, redact, rasterise to PNG. PDF and document export. The social share card, which is usually a fresh render rather than the original asset. The email digest, which inlines a re-encoded copy. And the API or webhook that hands the asset to somebody else’s system, which is the exit with the least review and the most consequence. Text has its own list and it is shorter and worse: a machine-readable mark on generated text survives almost nothing, so plan for the disclosure to be carried by the surface and by the record rather than by the string, and do not let a demo of text watermarking decide your architecture. Two structural answers fall out of that walk. Preserve where you can and re-sign where you cannot, which means your own transforms become signers rather than strippers, and the derived asset carries a manifest that names your product as the one that produced it from a source that itself carried one. And record it server-side regardless, so that for every asset you emitted you know which model and version produced it, which is what lets you regenerate a mark after the fact rather than reconstructing a provenance chain from support tickets. Then test it the way you test anything else: a fixture asset with a known manifest, pushed through every exit path in CI, asserting at each one that the credential is present and valid. That check is cheap, it runs in seconds, and it is the difference between a policy and a property. The boundary: we do this audit and build the preservation, signing and verification paths inside your product, we are not your counsel, and we make no determination about what your obligations are.
- A.
By designing the disclosure as a component with states rather than treating it as a sticker, which is the same move that works everywhere else in a design system. Start from what each regime actually asks, because the answer is narrower than the instinct to badge everything. The machine-readable mark is invisible by definition and costs the interface nothing. The visible obligation is targeted: under the AI Act it lands on deepfakes and on AI-generated text published on matters of public interest, and California’s manifest disclosure lands on covered developers’ own generated output. Most products conclude, wrongly, that this means a permanent badge on every AI-touched pixel, which is both more than is asked and less useful than what is asked, because a marker that appears on everything is read as decoration within a week and stops carrying information. Four design rules we hold to. Disclose at the level the user is making a decision, which is the asset in a feed or a detail view, not the page footer and not a line in your terms. Use one consistent mark across every surface, ideally the one your ecosystem already teaches people to read rather than a bespoke icon that has to be learned, and note that the Code of Practice points at a common EU label for exactly that reason. Make it progressive: a small persistent affordance that opens the full record, who generated it, with which model, when, what was edited afterwards, so the interface stays quiet while the detail is one interaction away for the person who wants it. And design the three verification states properly, because this is where products get it wrong and where the trust is actually won or lost. Signed and valid is the easy one. Signed and broken, meaning the content changed after signing, needs its own state and must never silently degrade to the valid one. And absent needs the hardest copy in the feature, because an absent credential means unknown and not human-made, and the honest string is something close to no provenance information rather than anything implying authenticity. That sentence is worth fighting for in the design review. Two more practical notes. Test the label against your real surfaces before you commit to it, feed, grid, lightbox, full-bleed hero, print stylesheet and email, because a disclosure that vanishes at one breakpoint or in one client is not a disclosure. And run it past accessibility properly: it needs a text equivalent, it needs to survive high-contrast and forced-colours modes, and it must not be conveyed by colour or by an icon alone. We build these components and their states inside your design system. We are not your counsel and we do not decide what you are obliged to disclose, and we would rather build the narrower thing your lawyers actually require than the badge your product team fears.
- A.
From the outside, in an afternoon, and the list is almost always longer than the team expects, because three separate layers can put a tool on your domain and only one of them is your code. Run the inventory the way an agent arrives rather than the way your architecture diagram is drawn. Load your real pages in a browser that speaks the protocol and enumerate the tools the page registers, on the marketing site, the signed-out product, the signed-in product and the checkout or upgrade flow, because the set changes per route and the interesting ones are behind the login. For each tool, record four things: its name and description, which is what the model actually reads when it decides whether to call it; its input schema; what it does when called, tested against a real account you do not mind disturbing; and, critically, who authored it. That last column is the point of the exercise. Some tools are yours. Some come from your commerce or content platform and are on by default, which is how a storefront ends up serving catalog, cart, checkout and order tools nobody on your team wrote. Some arrive from the edge, where a proxy can switch on prebuilt tool packs from a dashboard with no code change and no redeploy, so the change never appeared in a pull request and nobody was asked. And some come from a script you did not audit, which is the same third-party-script hole this site argues about elsewhere, pointed at a new surface. Then sort the list into four buckets and act on them in this order. Turn off anything that touches money, identity, permissions or destructive state and was not deliberately opened, because a tool exists whether or not your team decided it should. Instrument everything that stays, per tool, with call volume, failure point and outcome, since agent failures are silent by construction and today they are landing in your analytics as a slightly worse conversion rate with no explanation attached. Replace the generic tools that matter commercially with declared ones over your own capability layer, so the agent gets your entitlement, promotion, consent and limit rules instead of the platform’s approximation. And leave alone the read-only ones that genuinely help somebody find you, because the point of the exercise is not to close the surface. Two things worth checking on every tool that survives, and they are where the real risk is. Any tool that returns user-generated or externally sourced content is a prompt-injection path into whatever agent is driving, and it needs to say so in its output rather than handing the model a paragraph of somebody else’s instructions with no label on it. And any tool with an irreversible consequence needs the flag that asks the browser or the agent to get a human confirmation first, plus the interface to collect one. We run this audit and build what comes out of it inside your product. We do not manage your CDN or your commerce platform, we do not resell a tool pack, and which flows you open is your commercial decision rather than ours.
- A.
Replace the ones that carry commercial meaning and turn off the ones that carry consequence you did not intend, and the reason it is not simply "turn them all off" is worth being precise about, because both extremes lose something real. The case against switching everything off is that the traffic is arriving whether you serve it well or badly. An assistant that cannot call a tool does not go away, it falls back to driving your interface by reading the page, which is slower, far less reliable, produces exactly the half-finished sessions you cannot see, and gives you no schema, no logging and no confirmation point. Closing the declared surface does not remove agents from your product, it removes your ability to know what they did. The case against leaving the defaults in place is that they are not your product. A platform tool is written against the platform’s model of a store or a site, so it knows a cart and a catalog and does not know your trial gating, your seat entitlements, your regional pricing rules, your consent state, your fair-use limits or the three conditions your upgrade flow checks before it lets a purchase through. When the agent calls it, your rules are not in the path. That is not primarily a security problem, because the server still authorises the request and a schema was never a boundary, it is a correctness and revenue problem: the agent completes something your interface would have blocked, or blocks something your interface would have allowed, and either way the answer your customer got is not the answer your product would have given. So the shape of the fix is the one this site argues for everywhere else, and it is the reason we keep insisting the capability layer comes before the transport. One layer underneath, holding the rules, called by your own interface. Declared tools on top of it, which is a thin adapter rather than a second implementation of your product, so an agent and a human necessarily get the same answer because they went through the same code. Then the generic tool is replaced rather than merely disabled, and the flows you deliberately leave open are open on purpose with your logic in them. Sequencing matters more than it sounds. If you build the tools first and the layer later, you have shipped a second product that will drift from the first one within two releases, and the drift is invisible until a customer reports that your assistant disagreed with your app. Where to actually start, given nobody has the budget to do all of it: the flows where an agent completing the wrong thing costs money or trust, which is usually purchase, upgrade, cancellation and anything that changes permissions. Everything else can wait for the measurement to say whether agents are using it. Three limits. This does not make your product agent-operable on its own, since a declared tool still has to be reachable, idempotent and honest about failure. Replacing a platform default may cost you whatever aggregation that platform does on your behalf, and that is a trade to make with your eyes open rather than a free upgrade. And a tool your agent calls correctly can still be the wrong thing to have exposed, which is a product decision. We build the capability layer, the declared tools, the confirmation surfaces and the instrumentation inside your product, on your stack. We do not operate your platform and we do not sell you tools by the pack.
- A.
Fetch the page the way the crawler does and read what comes back, which takes about five minutes and is the most useful thing most teams have not done. Request the URL with no JavaScript execution, no cookies and no consent state, then read the response body as a document: can you answer, from that text alone, what the product is, what it costs, what it does, who it is for and what the page claims? Whatever is not in that response does not exist for the systems that answer on your behalf. This matters because the crawler population is not uniform and the difference is not a detail. Googlebot and Applebot ship a full renderer, and Google’s AI surfaces run on the same rendering infrastructure, which is why a client-rendered app can rank perfectly well in classic search. The retrieval bots behind ChatGPT, Claude and Perplexity do not render. The Vercel and MERJ analysis of more than 500 million crawler fetches found they take the HTML and leave, sometimes downloading JavaScript files (about 11.5% of GPTBot requests and about 23.8% of ClaudeBot’s) and never executing them, and vendor documentation through the first half of 2026 still describes the same behaviour for GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, PerplexityBot, Bytespider and CCBot. They also do not click, do not scroll and do not wait for your fetch to resolve. Run the test on the pages that answer buyer questions rather than on the homepage, which is usually the one page somebody already server-rendered: pricing, the product detail pages, docs, comparison pages, the FAQ, the integration list, and every page a sales conversation links to. In a React application the things that vanish are predictable enough to check for by name. Content loaded in an effect after mount. Anything behind a client-only route. A tab panel or accordion whose content mounts on click rather than being present and hidden. Prices, stock and availability that arrive from a client SDK. A reviews or ratings widget served by a third party. A list that only exists after infinite scroll. And structured data injected by a script, which is invisible for exactly the same reason as the copy around it. The output of the exercise is a short inventory: for each page that matters, what a non-rendering client receives, what is missing, and whether that page is an answer surface at all. One rule constrains every fix that follows, and it is worth stating before anybody reaches for a clever one: the HTML a bot receives has to be the page a human receives. Serving a fuller document to crawlers than to people is cloaking, it is a risk on the search side, and it creates two versions of your product truth where the one nobody looks at is the one the model quotes. We run this audit as part of a scoped build, and the free AgentReady scan covers the mechanical half of it if you want a number before you talk to anyone.
- A.
No, and the split is cleaner than it looks, because most of your application is not an answer surface and never will be. Nothing behind your login is crawled by anyone, so the logged-in product can stay exactly as client-rendered as it is today and the rendering decision only applies to the public pages that answer a question: marketing pages, pricing, product detail, docs, changelog, comparison and FAQ content. That is usually a small, well-bounded part of the codebase, and it is often already the part built on a framework that can render on the server if somebody turns it on. Four changes carry almost all of the value. Put the answer in the initial HTML, by server-rendering or statically rendering those routes, and keep interactivity layered on top rather than underneath: the page should be readable before hydration and better after it. Streaming is fine and does not need to be avoided, because streamed markup is still in the response body, as long as what streams does not depend on a fetch the browser has to make. Render structured data on the server alongside the copy it describes, since JSON-LD added by a client script is as absent as the text would be. And make content that is visually collapsed present in the markup rather than mounted on interaction, which on an FAQ or a spec table usually means native details and summary elements with the JavaScript adding the animation rather than the content. A bot-only prerender is a fallback, not the default, and it is worth being honest about why: it is a second rendering of the same page, it drifts from the first one, the drift is invisible because nobody on your team ever looks at the version the bots get, and you now depend on a vendor’s timeout and cache behaviour for whether your product is described correctly. It is a reasonable bridge for a legacy app that genuinely cannot be moved. It is a poor destination. Three limits, and the third is the one that matters commercially. Rendering makes you readable, it does not make you citable: a page an assistant can read and still has no reason to quote gains nothing, and no rendering strategy substitutes for having a specific answer on a specific page. Readable is also not operable, which is the other half of this service: an assistant that can read your pricing page still cannot complete anything in your product without declared tools over a capability layer. And none of this is a ranking guarantee in any engine, because none of us controls retrieval. What it does is remove the failure mode where the answer exists, the page exists, and the machine that was asked about you received an empty div. We do this inside your existing Frontend, route by route, as a scoped fixed-price build. We do not replatform your application and we do not sell you an SEO retainer.
- A.
More than a version bump and less than a rewrite, provided the capability layer underneath it was ever separated from the transport. The headline is that MCP moved from a bidirectional stateful protocol to a request and response stateless one. The initialize and initialized handshake is gone, and so is the session header that went with it. Each request is now self-describing, carrying the protocol version, the client identity and the capabilities in its metadata, which is what lets a server sit behind an ordinary round-robin load balancer with no shared storage, and that single change is why the release was worth a clean break. Around it sit four things worth knowing before you plan the work. Server-initiated requests that used to need an open stream are replaced by multi round-trip requests: a tool that needs input mid-call returns a result type of input required along with what it needs answered, and the client retries the original call with the answers attached. Streamable requests now carry method and name headers, so your gateway, rate limiter or WAF can route and meter on a header instead of parsing a JSON body, which is the first time this protocol has been operable by the infrastructure teams already run. List results became cacheable, carrying a time to live and a cache scope, so a client stops re-fetching a tool list that has not changed. And authorisation hardened: authorisation servers must return the issuer parameter from RFC 9207 and clients must validate it, client credentials are bound to the issuer that minted them, and Dynamic Client Registration is formally deprecated in favour of client ID metadata documents, though it keeps working for now. Then the part to diarise rather than debate. Roots, sampling and logging are deprecated, and so is the legacy HTTP and SSE transport, each with a year-long offramp, under a new policy that requires at least twelve months between a deprecation and the earliest possible removal. Tasks moved out of the experimental core into an official extension with a polling lifecycle, which means anyone who shipped against the experimental tasks API from the 2025-11-25 revision has a real migration rather than a rename, and the resource-not-found error code changed, which is the kind of detail that breaks a client quietly. MCP Apps, the extension that carries the interface an assistant renders, is now versioned independently of the core, which is the most under-reported good news in the release: your UI work is no longer hostage to the transport’s release cycle. The order we do this in is always the same, and it is the order that makes the next revision cheap rather than this one. Pin and assert the version first, because a date-based version string is a contract and an integration that does not test against a named revision is an integration that will find out from a customer. Separate the adapter from the domain second, if that has not already happened: what a task, a record or a transaction means in your product is yours and no specification defines it, while the protocol layer translates, and the moment a protocol’s data model reaches your database you have coupled your roadmap to somebody else’s. Then migrate the transport, then the auth, then the deprecated capabilities, each behind its own contract test. Two limits. Twelve months is a floor rather than a promise about any particular client, and hosts move at their own pace, so the honest plan tests against the revision each host actually speaks rather than against the newest one published. And none of this makes a server get picked by a model, which is a different problem with a different fix. We build the capability layer, the adapters and the migration inside your product and your repository. We are not the protocol’s maintainers, we do not speak for the specification, and we do not promise you behaviour a revision has not shipped.
- A.
That the state was never supposed to live in the connection, and the revision has stopped letting you pretend otherwise. Most first-generation servers were built the way a WebSocket application is built: the client connects, the server remembers who it is talking to, and everything after that leans on the fact that a particular process is holding a particular conversation. That is what made these servers awkward to run, because a stateful connection cannot be load balanced without sticky sessions or shared storage, cannot be redeployed without dropping work, and cannot be scaled by adding instances. The stateless core in the 2026-07-28 revision removes the handshake and the session identifier and makes each request self-describing, which moves the question from how do we keep the connection alive to where does this state actually belong. On a well-built product the answer is the same as it is everywhere else in your system. Conversation-scoped context belongs to the caller and rides on the request. Work that takes longer than a request belongs to a durable record with an identifier your product already understands, which is what the tasks extension now formalises with a polling lifecycle and change notifications rather than an open channel. Anything a retry could duplicate carries an idempotency key, because a stateless transport makes retries ordinary rather than exceptional, and a tool that charges money or sends a message is the one place where being called twice is not a rounding error. And the expensive parts of a listing are cacheable now, with a time to live and a cache scope declared by the server, so a tool list stops being re-fetched on every turn. What this buys you is unglamorous and large: the server deploys like the rest of your application, scales horizontally, survives a rolling restart, and can be metered and rate-limited by the infrastructure your team already operates, because the routing information is in the headers. What it costs is a real piece of design work in the middle, and it is the same piece of work every other answer on this page argues for. If your tools call into a capability layer that expresses what your product can do, the migration is an adapter change. If your tools are a thin wrapper around a connection that held everything, it is a rebuild of the part you skipped. Two limits, both worth saying before anyone scopes this. A stateless protocol does not make your product stateless, and a long-running job still needs somewhere durable to live, which is a design decision about your domain rather than a setting. And hosts adopt revisions on their own schedule, so for a period you will support more than one, which is an argument for the adapter boundary rather than against the migration. We build this inside your own service and your own infrastructure. We do not host your MCP server, we do not resell a gateway, and we do not speak for the specification.
- A.
We scope it as a Frontend build with a measured budget, because that is what it is: the model is a component in it and almost never the part that decides whether it works. The bar is human. When Stivers and colleagues recorded question and answer sequences in ten languages, from Japanese and Korean to Italian, Danish and Yélî-Dnye, and published the result in PNAS in 2009, every language produced the same shape, a unimodal distribution of speaker transitions peaking inside the first 200 milliseconds after the question ends. Nobody chose that reference and nobody can be talked out of it, which is why a correct answer at a second and a half reads as broken and the same answer at four hundred milliseconds reads as a conversation. The budget is therefore the spine of the scope, and it is spent across capture, endpointing, transport, inference, first audio and playback, of which the Frontend owns four. A scoped build has four phases and a fixed price against them. The first is the budget itself, measured on your path rather than assumed: we instrument a thin end-to-end path through your real provider, your real tool calls and your users’ actual network, and we find out where the time goes before anything is designed, because the answer differs enough between products that starting from a published figure is guesswork. The second is the conversation mechanics: endpointing tuned per surface, since a dictated form field is not a support conversation and a threshold that feels right in English is wrong in Hebrew; barge-in built properly, meaning voice activity detection on the capture stream, echo cancellation so the assistant’s own output does not come back through the microphone and trigger it, cancellation of in-flight audio and of the generation behind it on the first syllable, and the reconciliation step almost everyone skips, where the system works out what the user actually heard rather than what the model believes it said. The third is the surface: the transcript rendered and correctable, tool results rendered rather than only spoken, confirmation before anything irreversible, and a text path that is first-class rather than a fallback, because voice is a second modality and not an accessibility feature and a product with voice only has removed a mode from the people who cannot use it. The fourth is the operational half: per-turn instrumentation, a domain vocabulary so your own product names and customer names stop being transcribed as something else, and an evaluation set built from your recorded audio rather than a vendor benchmark. What we need from you is short and it is the part that stalls projects when it is missing: a decision about the provider or a mandate to choose one with you, recorded audio from real users or permission and a path to start collecting it, the list of actions voice is allowed to take and which of them are irreversible, and one person who can answer what the product should do when the recogniser is wrong. Limits we state before the scope is signed. We do not quote you a latency number, because every published figure comes from a demo on a good connection and the only honest one is measured on your path. We do not promise recognition quality, which is a provider property you will re-evaluate when the provider changes. And we are not a contact-centre vendor: no telephony, no IVR, no outbound calling, no call-centre analytics. We build in-product and in-browser voice inside your codebase, on your provider and your infrastructure, and we run one of these on this site.
- A.
The demo conditions, almost every time, and they are worth listing because each one maps to a specific defect. A demo is a quiet room, one speaker, a good headset, a short session, a clean network, and vocabulary the recogniser has already seen. Real use is none of those, and what surfaces is a predictable set. Turns get cut off, because endpointing tuned on fluent demo speech treats a real pause for thought as the end of a sentence, and being interrupted mid-thought is the complaint users actually escalate. Barge-in fires on the wrong thing, either the assistant’s own audio returning through the microphone because echo cancellation was never requested on the capture stream, or a colleague talking nearby. The transcript drifts over a long session, so the model is reasoning about a conversation that diverges from the one that happened. Tool calls get grounded in a mis-heard word, and the words most likely to be mis-heard are precisely the ones your product depends on, your own product names, order numbers, customer names, anything Hebrew or code-switched. And the expensive one: the agent says it did something and the call behind it failed, which is not a voice defect at all, it is an interface reporting intent as outcome, and voice hides it better than a screen does. The fixes are unglamorous. A domain vocabulary supplied to the recogniser as a biasing list rather than as a sentence in a prompt, built from your own catalogue and names, since this is the highest-yield change on most products and it is usually a day of work. Confirmation before consequence, rendered rather than spoken, for anything that spends money, sends a message or changes state, with the threshold being whether the user could tell afterwards that it happened rather than whether the model was confident. Spoken confirmations generated from the tool result and after it, never from the intent, so "done" means the call returned. Session state that survives the connection: a long call is not one socket, the context lives on the server, the transcript is durable, and a reconnect resumes rather than restarts. And measurement at the turn rather than the call, because a call-level success rate hides everything: time to first audio, interruption rate, the share of turns where the user had to repeat or correct themselves, the share of tool calls grounded in a transcript the user then corrected, and the point at which people give up. Then the part that makes the difference durable, which is the evaluation set. It is built from your own recorded audio, with the accents, background noise, devices and code-switching your users actually have, and it runs on every change to the prompt, the vocabulary, the endpointing thresholds or the provider, because all four of those are things somebody will adjust on a Friday. A vendor benchmark tells you how the provider performs on the provider’s audio. Limits. None of this repairs a recogniser that cannot hear your users, which is a provider decision you make with your own recordings and re-make when the provider ships a new model. A voice interface does not make a poor flow good, it makes a poor flow faster to reach, so if the underlying action is confusing on screen it will be worse in speech. And we do not publish latency or accuracy figures for your product or for anybody else’s, because the only ones worth acting on are measured on your own path. We build and instrument this inside your product, on your provider and your data. We are not a contact-centre vendor and we do not resell a speech provider.
- A.
Less than the question implies, and the part that is yours is the part that gets skipped. Begin with the distinction, because most of the confusion in this conversation is definitional rather than technical. MCP is vertical: an agent reaching down to a tool, a data source or your product. A2A is horizontal: one agent handing a unit of work to another agent it does not own and cannot see inside. They are not competitors and you will very likely speak both, which is exactly why conflating them produces bad architecture decisions. Then the status, dated deliberately because this is the fastest-rotting paragraph on this page and we re-check it rather than repeat it from memory. A2A came out of Google in April 2025 and became a Linux Foundation project that June. It now sits beside MCP under the Agentic AI Foundation, which the Linux Foundation formed on 9 December 2025. Version 1.0 arrived on 12 March 2026 as the first stable release, and its most consequential addition was cryptographically signed Agent Cards, so that a receiving agent can verify a card was genuinely issued by the domain it claims. By the protocol’s one-year mark on 9 April 2026 the project reported more than 150 supporting organisations and deployments inside the major cloud agent platforms. Mechanically the shape is modest. You publish an Agent Card at a well-known URL on your own origin, declaring the skills you offer, the transports you accept and the security schemes you require. Work is modelled as a task with an explicit lifecycle, including states for work that is sitting waiting on a person. Transport is JSON-RPC over HTTP with gRPC and plain HTTP bindings alongside it, streaming for progress and webhook notifications for work that outlives a connection. Now the part we would say to you before you scope anything. Most products asking this question do not have an agent for another agent to delegate to. If the capability layer is not built, A2A is premature, and the honest answer to give your customer is a date rather than a card. Publishing a card that describes skills you have not built is worse than publishing nothing, because it is a discoverable, signed, machine-readable promise. Where the capability layer does exist, A2A is simply one more caller onto behaviour you already have. That is the same layering argument we make about the MCP revision and about WebMCP, and we repeat it on purpose because it is the single decision that determines whether the next protocol costs you an adapter or a rewrite: the capability layer survives the protocol, the adapter absorbs it, and a second or third implementation of your own product is a second or third source of truth that will drift. What is genuinely Frontend work here is small, and it is skipped almost every time. The Agent Card is a published claim served from your web origin, which makes it a deployment artifact that goes stale exactly the way llms.txt and a sitemap go stale, so it is generated from the capability layer rather than hand-maintained in a file somebody edited once. A task that needs input or authorisation is a person’s problem arriving without a person attached, so those lifecycle states need a real interface rather than a log line. And whatever a remote agent did inside your product has to be legible and reversible by a human who was not in the room when it happened. The limit is the sentence worth carrying into the meeting where somebody is excited about this. The 2026 governance analysis of agent interoperability protocols states it directly: an agent exists purely by publishing an Agent Card, there is no protocol-native concept of membership, admission or removal, and the protocol is agnostic to liability with no native mechanism for reputation or trust. Interoperability is therefore not trust. Speaking A2A says another system can reach you in a defined way. It says nothing about who is permitted to act on whose behalf, what they may spend, or who carries the loss when it goes wrong, and all three of those remain in your contracts, your authorisation model and your own product decisions. We build the capability layer, the card generation and the adapters inside your repository. We are not the protocol’s maintainers, we do not speak for the specification, we do not host your agent, and if you do not need this yet we will tell you so and say what to build instead.
- A.
Everything it owed them while they were watching, delivered afterwards instead of during, and this is precisely the half that no protocol can do on your behalf. A2A, MCP and everything after them describe how the request arrives. What the person gets back is a product decision, and four things carry it. First, an authority the user actually granted, captured before the work and narrower than their own. Their own permissions are a ceiling and never a floor, which sounds obvious and is violated constantly by integrations that run as a service account with more access than any human involved. The grant names what the agent may do, over what scope, for how long, and it is revocable from a surface the user can find on their own rather than by emailing support. Second, a pause that is a real surface. A task lifecycle with states for needing input or needing authorisation means your product is going to hold work waiting on a human, and the moment that is true you have an inbox, not a modal: addressable by URL so it can be sent to the person who can actually decide, resumable after a reload, and surviving the originating agent disconnecting entirely. This is the single most common thing teams discover late, because in a demo one person watches one task from start to finish and the waiting state never renders. Third, a receipt written for a human rather than for a machine. What was requested, by which agent, under whose grant, what changed, when, and what reverses it, with the real parameters rendered rather than summarised into a sentence, living in the same activity record your support team already reads back to customers. Fourth, a refusal that is legitimate. Irreversible or consequential actions do not complete with nobody present; they queue for the person. And deciding that an entire class of work is never delegable is a normal product answer rather than an engineering failure, which is worth saying explicitly because teams feel obliged to make everything callable once they have built the plumbing. Then the mechanics, without which the four above are a slide rather than a system. The delegated call runs the same typed function your own button runs, so validation, permission checks, telemetry and audit are inherited instead of reimplemented on a path that will then drift. Every call carries an idempotency key, because a retry from an agent whose logic you do not control is ordinary rather than exceptional, and a duplicated side effect is the failure users escalate. And a contract test runs the same case through both callers and fails the build when they disagree, so a rule you changed for the interface cannot quietly stay old for the agent. It is worth placing this beside its neighbours on this page, because they get blurred in scoping conversations and they are genuinely different questions. Whether you serve automated callers at all is access policy. Who is calling is verified identity. Whether a caller can complete a flow designed for people is operability. What a transaction looks like with an agent as a party to it is commerce. This one is narrower and later than all of them: it is what you owe the person whose work was carried out while they were somewhere else. Limits. None of this makes the remote agent behave, and nothing you build can; it makes what the agent did legible, attributable and reversible, which is a smaller claim and the only honest one. A receipt nobody reads is not consent, which is why the grant is captured before the work rather than implied by the fact that work happened. And where money, personal data or a regulated decision is involved, the binding rules are your counsel’s and your data protection officer’s rather than ours, and we build to what they tell us. We build this inside your product, on your infrastructure and your data. We do not operate your agent, we do not become a party to your customer relationships, and we are not auditors and we certify nothing.