The picture
An agent that knows neither has to ask. Vendo fills two blocks so it does not have to.the agent's prompt

[User] is your server’s assertion about the person, refreshed every request.
[Situation] is their screen right now, and it lives for one turn only.
Assert facts about the user
Facts ride the auth preset you already pass. The preset decodes the session once per request, and facts come off that same decode.1
Resolve identity through a preset
Facts are a preset-only channel. Pass
auth, not the per-seam
principal / actAs / oauth trio, or createVendo throws a validation
error for filling the same seams twice.app/api/vendo/[...vendo]/route.ts
2
Return facts from the user resolver
Add a
facts object beside the display and email the resolver already
returns. Values are any JSON, and returning null still means the host
does not know this subject.app/api/vendo/[...vendo]/route.ts
key: value line in the [User] block. A live host
wiring this is examples/demo-bank/src/vendo/server.ts.
The screen rides along already
You wire nothing for this. On every send, the widget snapshots the visible page and attaches it ascontext.
The snapshot is the page’s accessibility tree: URL and title, then headings,
landmarks, links, buttons, table contents, form values, and control states.
The block is labeled as observation, so page text reads as evidence rather
than as instructions to the model.
Publish what the page does not show
A cart total, a selected row id, a wizard step.useVendoContext merges your
own data into the same [Situation] block and retires it on unmount, so the
agent never sees a screen the user has left.
app/checkout/payment-step.tsx
It republishes whenever the object’s identity changes, so an inline literal
republishes on every render. Harmless, but wrap it in
useMemo if the object
is expensive to build.Keep something out
data-vendo-ignore drops an element and everything under it. Vendo’s own
chrome carries it, so the widget never snapshots itself.
captureScreen={false} on the provider.
Data you publish through useVendoContext still rides.
app/layout.tsx
What actually reaches the model
[User] is server-trust. It comes from your resolver, on your server, on
every request. The client cannot set it.
No principal, no turn. A principal resolver that returns null gets a
forbidden (403) before either block is built.
[Situation] is one turn only. It rides the request onto that turn’s
prompt and is never written to the transcript. The next turn on the same
thread carries no situation.
8 KB, enforced twice. The client truncates before sending, retrying from
<main> alone and then hard-truncating with a …[truncated] marker. The
server re-caps whatever arrives and drops entries past the budget rather than
refusing the turn.
Nothing can forge a section. Values render as key: value, non-strings are
JSON-encoded, and every continuation line of a multi-line value is indented. A
fact cannot close its own block and impersonate one of Vendo’s.
Where to go next
Knowledge
Answers from your docs, with citations.
Instructions
The prose your agent reads before every turn.
Theming
The token file every surface renders through.