The guide that
walks one step
ahead of you.
Virgil reads the screen your user is actually looking at, decides what they should do next, and points at it. No scripted paths, no selectors to keep in sync, nothing to rewrite when a button moves.
- 0
- selectors to maintain
- 1
- component to mount
- any
- AI SDK provider
Live · the real package, on a fictional back office
A written tour is a promise about an interface that no longer exists.
You write the path by hand. Step three is #supplier-select. A designer renames it on a Tuesday. The tour keeps running and points at nothing, and nobody notices until a customer does.
Nothing is written down. The question asked is given this screen and this goal, what should the user do next? — and it is answered against the screen that actually rendered.
Rename the button and the guide still finds it, because it was never looking for a name.
Three moves, repeated until the goal is reached.
Read
A deterministic pass over the DOM collects what can be acted on right now: role, accessible name, section, destination, whether a field is already filled. No model touches this path — it is free, and it is where privacy is decided.
Decide
The model gets the goal, the steps already taken, and that list. It answers with an id from the list — never a selector, never a label it made up. It cannot point at something that is not on screen, because there is nothing else it can name.
Point
The cursor travels to the element, the reticle locks on, and one sentence says what to do and why. The step completes on the click, on the route change, or on the user confirming they looked. Then the next one is decided.
Or point at the thing you don’t understand.
Not everyone can name what they want. Switch the mode on — from your own toolbar, or with Mod+I — and the pointer outlines whatever it is over. Click it and you are told what it is and what happens if you use it, with no question typed.
It is a mode, and it says so: while it is on, it takes the app’s clicks. Escape, the same button, or a click anywhere outside the answer all give them back.
Live · sweep the pointer, then click something
What your app calls things, not what it shows.
Roles, authored labels and structure are forwarded. A field is described as [filled] or [empty] — its value is never read. Inside a row, a cell, or anything you mark data-virgil-data, the text stays behind too: those become “a cell in Supplier”.
Bring your own model
Any Vercel AI SDK provider. Your key, your account, your choice of model for chat and for step decisions.
If the guide breaks, it removes itself and your app carries on.
An assistant is never worth a white page.
Per-page knowledge
Drop a companion.md next to a route and the guide learns that screen. Build-time generated, checkable in CI.
Speaks your language
Prompts and copy are configurable, not translated. Ship the guide in the language your product is in.
Off by default
Gated by a build flag and a user switch. Until both are on it renders nothing and registers no listeners.
One component, one route handler.
Mount it once in your dashboard layout and hand the handler a model. There is no step three.
import { createVirgilHandler } from "virgil-ui/next" import { openai } from "@ai-sdk/openai" export const { POST } = createVirgilHandler({ model: openai("gpt-5.6-terra"), auth: async () => Boolean(await getSession()), })
import { Virgil } from "virgil-ui/react" <Virgil /> // that is the whole integration
See it find its own way.
The demo is a working back office nobody has ever used before. Give it a goal in plain words and watch it work out the path.