.vendo/overrides.json is the human layer of .vendo/. vendo sync
regenerates tools.json wholesale on every run and never touches this file, so
this is where a correction survives.
Three layers merge per tool, in order: deterministic extraction
(.vendo/tools.json), the AI pass (.vendo/judgments.json), then your
overrides. Overrides win field by field, and they are the last word.
.vendo/overrides.json
tools even when it is empty — it is a required key. The file is strict
on purpose: a typo in a hand-written override fails loudly rather than being
silently ignored. compounds, briefs, surfaces, and remix are the only
other top-level keys.
Per-tool fields
Raising risk lapses old grants. The next call parks a fresh approval that names
the invalidated grant, and audits one
grant-invalidated decision.
A grade you pin here holds for every tool, listed or not. A
connected-account tool the agent found by
searching the provider’s catalog is graded live off the provider’s own tag —
name it here by the provider’s tool id and your grade beats that tag, the same
way it beats extraction for a tool of your own.
Field semantics
semantics is annotation on the tool’s response, keyed by dot path with
array levels collapsed — data.amountCents covers /data/3/amountCents. It is
the highest authority for that field: your annotation beats sync’s inference.
.vendo/overrides.json
money (unit cents or dollars, optional currency), date
(format iso or epoch), enum (labels), id (optional entity),
percent (scale ratio or 0-100), code, and plain. code is an
identifier a person reads — a sha, a branch, a ticket key — as opposed to id,
a handle a screen passes back to a tool and usually never shows.
Compound tools
The same file’scompounds array bundles a short sequence of existing tools
into one capability the agent calls by name. Compounds live only here, never in
tools.json — a compound entry inside tools.json is rejected.
.vendo/overrides.json
Step shape
Every expression is evaluated against
{ args, steps, item }, not taken as a
literal — that is how steps.create.id hands one step’s output to the next. A
compound holds between 1 and 50 steps, and a forEach may not exceed 1000
items.
The two rules the loader enforces
Once the file parses, two more checks run against the merged result:riskmust equal the maximum of the step risks.ungradeddominates that maximum — a compound cannot claim to know its own risk while one of its steps is ungraded.- A step may only name an enabled primitive host or connector tool. Never
another compound, never a capability tool registered through
add().
actAs.
Remix scanning and briefs
remix has two keys, both read by vendo sync.
.vendo/overrides.json
host/ and its screens in ../demos/ land in one sync. Captured
module ids stay relative to the project root, so a file under an extra source
reads as ../demos/maple/NetWorth.tsx. A path that is not a readable directory
warns and names itself rather than quietly contributing no wrappers. See
Import & fork.
briefs is the last top-level key: { name, text, tools? } entries of reviewed
prose attached to primitive tools. It parses and validates today, but nothing
consumes it yet, so writing one changes nothing.
The fields defineTool does not ask for
defineTool returns a plain ToolDefinition, so every descriptor field the
helper does not ask for is a spread away.
confirmEach makes every call earn its own approval, whatever the policy says.
title is the human label approval cards and tool menus show.
What the helper does ask for is fixed:
inputis the single statement of the arguments. It becomes the JSON Schema the model is shown and the parse that runs beforeexecute, so the two can never drift apart. A call that does not match is refused before your function runs.riskis required, and it is a grade:read,write, ordestructive. You wrote the tool, so you know. Only extraction is allowed to answerungraded.contextis the run context —context.principalis whose authority the call carries.executereturns the output, or throws. The denial outcomes belong to the guard: nothing you write can fake an approval.
Curated menus and hand-written tools
surfaces.agent and surfaces.mcp each name the tools that one surface
offers. A menu is curation, not a permission boundary: it decides what a
surface offers, never what the guard allows.
.vendo/overrides.json
surfaces.mcp names a menu, add host_refundOrder to it —
otherwise the door will not offer it, and a call to it answers the same
not-found an unknown name gets. Vendo’s own vendo_* tools bypass the menu and
always ride along; yours does not.
Forget to add it, and Vendo warns once per surface per boot, naming the tool you
left out — but the warning does not add it for you. See
Curate the menu.