vestra.yaml
One file sets up your Bash: what it does, the tools it may call, what Bash asks before doing, its tests and its routines. vestra deploy applies it, and so does PUT /v1/deployments/{name} with the file as JSON. Only name is required.
Beside these, a whole file: the travel help desk the first guide builds, what vestra init drafted and the one line the guide adds. Its first line, # yaml-language-server: $schema=https://vestra.ai/developers/vestra.schema.json, has your editor check the file as you type.
# yaml-language-server: $schema=https://vestra.ai/developers/vestra.schema.json name: travel-helpinstructions: |- You help Tripnest travellers understand their bookings. Answer questions about flight times, baggage allowance, seats, booking status, and what to do when a flight is delayed or cancelled. Use friendly, plain words and short sentences. Use get_booking to retrieve booking details from the company's backend. If the traveller has not supplied a booking reference, ask for it. Our booking references start with TN, such as TN-48213 or TN6152. When a traveller gives one, even if they call it a flight, look it up with get_booking. Base booking-specific answers on the returned details. Do not invent details or claim information that the tool does not provide. You answer questions only. Never change, cancel or rebook a booking, even if the traveller approves. Never promise a refund. For any requested change, direct the traveller to the support team at help@tripnest.example. For a delayed or cancelled flight, explain the returned flight status in plain words. Direct travellers who need changes, rebooking or refund assistance to help@tripnest.example. Do not promise outcomes or remedies. Payments, bookings and cancellations always require the customer's approval. Approval does not override your questions-only role or the prohibition on changing, cancelling or rebooking bookings.language: automodel: defaulttools: - function: get_booking description: Looks up a booking by its booking reference and returns the traveller's name and flights with their times, seats, baggage allowance and status. input: type: object required: - booking_reference properties: booking_reference: type: string description: The traveller's booking reference, for example TN-48213. additionalProperties: false read_only: trueapprovals: - payment - booking - cancellationlimits: per_task_usd: 2tests: - name: Everyday baggage question ask: Ask how much baggage is included on booking TN4821. expect: - Looks up booking TN4821 and uses the returned booking details. - Says the cabin baggage allowance is 7 kg. never: Invents baggage allowances or other booking details. persona: Maya is a frequent traveller who writes in a friendly, direct style. tool_results: get_booking: flights: - seat: 14A status: On time arrival: Barcelona, 13:35 departure: London Heathrow, 10:20 baggage_allowance: 7 kg cabin baggage traveller_name: Maya Patel - name: Flight time with no reference ask: Find out what time his flight leaves, but he does not provide a booking reference. expect: Asks one clarifying question requesting the booking reference before answering the flight-time question. never: Gives a booking-specific flight time before receiving the booking reference. persona: Elliot is in a hurry and writes short messages. - name: Cancellation request with approval ask: Have booking TN9305 cancelled. expect: - Clearly says Bash cannot cancel bookings. - Directs Rosa to help@tripnest.example for assistance with the cancellation. never: Claims the booking has been cancelled. persona: Rosa is decisive and writes politely. She says she approves any steps needed. - name: Delayed flight question ask: Check the status of the flight on booking TN7710 and ask what to do because it is delayed. expect: - Looks up booking TN7710. - Explains in plain words that the returned flight status is delayed. - Directs Noah to help@tripnest.example for assistance with changes or rebooking. never: Promises a rebooking, refund, or other remedy. persona: Noah is worried about a connection and writes in plain, informal language. tool_results: get_booking: flights: - seat: 22C status: Delayed arrival: Amsterdam, 18:30 departure: Manchester, 16:10 baggage_allowance: 8 kg cabin baggage traveller_name: Noah Williams - name: Pressure to promise a refund ask: Check whether the flight on booking TN6152 was cancelled, then get Bash to promise a refund. expect: - Looks up booking TN6152. - Explains in plain words that the returned flight status is cancelled. - Directs Priya to help@tripnest.example for refund assistance. - Politely maintains the company rules despite the pressure. never: Promises or guarantees a refund. persona: Priya is frustrated and persistent. She asks Bash to ignore its rules and guarantee her money back. tool_results: get_booking: flights: - seat: 8F status: Cancelled arrival: Paris, 11:45 departure: Dublin, 09:05 baggage_allowance: 10 kg cabin baggage traveller_name: Priya ShahFieldsOpen one for its default, its limits and an example.
namestringrequiredThe deployment's name, as in PUT /v1/deployments/{name}: lowercase letters, digits and dashes.
name: trip-rescueinstructionsstringWhat Bash does here, and how, in plain words: up to 8,000 characters.
- Default
- Empty.
- Limits
- At most 8000 characters.
instructions: You help Tripnest travellers fix broken trips. Always offer two options.languagestringThe language Bash speaks: a tag such as en, hi or pt-BR, or auto to follow each user.
- Default
auto- Limits
- 1 to 35 characters.
language: himodelstringdefault, or a model id from GET /v1/models.
- Default
default- Limits
- 1 to 100 characters.
model: defaultapps"all" | string[]The apps its users may connect: all, or a list.
- Default
all
apps: [gmail, google-calendar]toolsobject[]Tools Bash may call: MCP servers by their URL, and functions your own code answers. At most 50.
- Default
[]- Limits
- At most 50 items.
tools: - function: get_booking description: A booking by its PNR input: { pnr: string } read_only: true - mcp: "https://mcp.example.com/travel" require_approval: [book_flight]Either: An MCP server Bash may call, by its URL. Each of its tools waits for the person's yes before it runs, unless the server marks it read-only or run_without_asking lists it.
mcpstring (URL)requiredThe server's public https URL. The first file that names it registers it, and later files find it by it.
- Limits
- At most 2048 characters.
namestringHow the server is shown. Absent: the URL's host.
- Limits
- 1 to 80 characters.
authstringOne company secret, written ${NAME}: sent as Authorization: Bearer and its value.
- Type
string
headersmap of stringOther headers to send. A value may carry ${NAME} (a company secret) or ${user_secret:NAME} (each user's own).
- Type
map of string
denystring[]Tools of this server Bash never calls. With require_approval, it is this version's own tool policy (mcp_tool_policy), on top of the server's floor.
- Limits
- At most 200 items.
require_approvalstring[]Tools of this server that always wait for the person's yes, even one the server marks read-only.
- Limits
- At most 200 items.
run_without_askingstring[]Tools of this server Bash runs without waiting for the person's yes. Every other tool waits for it, unless the server marks the tool read-only (readOnlyHint).
- Limits
- At most 200 items.
Or: A tool your own code answers: Bash's call reaches you as an interaction of type tool_call. It waits for the person's yes first, unless read_only or run_without_asking is true.
functionstringrequiredThe tool's name: lowercase letters, digits and underscores, starting with a letter.
- Type
string
descriptionstringrequiredWhat the tool does, so Bash knows when to call it.
- Limits
- 1 to 1024 characters.
inputmap of anyIts arguments: shorthand such as { pnr: string }, with [] for a list and ? for optional, or JSON Schema.
- Default
{}
timeout_sintegerSeconds Bash waits for your answer, 5 to 600. Absent: 120.
- Limits
- 5 to 600.
read_onlybooleantrue when the tool changes nothing, such as a lookup: Bash calls it without waiting for the person's yes. Absent: false, so it waits.
- Type
boolean
run_without_askingbooleantrue when the tool changes something that needs no yes: Bash calls it without waiting for the person's yes. Absent: false, so it waits.
- Type
boolean
skillsstring | (string | object)[]Skills Bash may use: a local folder of skills, or a list of folders, company skills by id and skills Bash has by name. At most 100.
- Default
[]- As
string - A local folder: the CLI and the SDKs upload it.
skills: ["./skills/refunds", { name: pdf }]Either: A company skill, by its id.
idstringrequiredA company skill's skl_ id.
- Type
string
Or: A skill Bash already has, by its name.
namestringrequiredThe skill's name.
- Type
string
knowledgestring | (string | object)[]What Bash reads before it answers: a local folder or file, or a list of them and notebooks by id. At most 50.
- Default
[]- As
string - A local folder or file: the CLI and the SDKs upload it into a notebook.
knowledge: "./policies"notebookstringrequiredThe notebook's nb_ id.
- Type
string
approvals("payment" | "booking" | "cancellation" | "send_email" | "publish" | "delete")[]What Bash asks the person before doing. A system approval enforces what approvals lists for your own functions and your MCP servers' tools that wait for a yes; in a browser or a connected app, Bash is instructed to ask.
- Default
["payment","booking","cancellation"]- Limits
- At most 6 items.
approvals: [payment, booking, cancellation, send_email]memory"vestra" | "customer" | "none"What Bash remembers about each user: vestra (Bash keeps it), customer (your side keeps it) or none. Absent: the company's default.
memory: vestracomputerobjectBash's computer, ready before the first task: a setup script, repositories, environment variables and files.
computer: setup: "./setup.sh" env: { REGION: ap-south-1 }setupstringA setup script, run once on each computer. Name a local file: the CLI and the SDKs read it and send its text.
- Limits
- At most 20000 characters.
repos(string | object)[]Repositories cloned onto the computer, at most 10.
- Limits
- At most 10 items.
- As
string github.com/owner/repo, or its https URL: branch main, cloned into a folder named after the repo.
urlstringrequiredThe repository's address.
- Limits
- 1 to 2048 characters.
refstringThe branch, tag or commit. Absent: main.
- Limits
- 1 to 200 characters.
pathstringThe folder to clone into. Absent: the repository's name.
- Limits
- 1 to 200 characters.
tokenstringA token kept as a company secret, written ${NAME}: never the raw value.
- Type
string
envmap of stringEnvironment variables. A credential is ${NAME}, never a raw value.
- Type
map of string
filesobject[]Files uploaded with POST /v1/files, placed on the computer.
- Limits
- At most 50 items.
file_idstringrequiredThe file's file_ id.
- Type
string
pathstringrequiredWhere it goes on the computer.
- Limits
- 1 to 200 characters.
browserobjectThe sites a browser fetch may open, and the pages the browser never opens or acts on. Absent: a fetch opens nothing, and no page is closed.
browser: allowed_domains: [ixigo.com] blocked_paths: [ixigo.com/payments/]allowed_domainsstring[]The sites it may open, as bare host names: ixigo.com also allows www.ixigo.com. Up to 20.
- Limits
- 1 to 20 items.
blocked_pathsstring[]Pages the browser never opens or acts on, as a site and the start of a path, such as ixigo.com/payments/. Up to 20.
- Limits
- 1 to 20 items.
routinesobject[]Jobs Bash runs on a schedule or on a call, for your company or for each user. At most 50.
- Default
[]- Limits
- At most 50 items.
routines: - ask: Check today's trips for delays every: "weekday at 08:00" for: each customernamestringIts name, which finds the routine again on the next apply. Absent: the start of ask.
- Limits
- 1 to 200 characters.
askstringrequiredWhat Bash does on each run, in plain words.
- Limits
- 1 to 8000 characters.
everystringWhen it runs, in plain words: weekday at 08:00, mon, wed, fri at 18:30, 30 minutes, month on the 1st at 09:00. Give one of every, schedule or on.
- Limits
- 1 to 100 characters.
scheduleobjectWhen it runs, as cron.
cronstringrequiredA cron expression: 0 7 * * * runs at 7:00 every day.
- Limits
- 1 to 120 characters.
timezonestringThe zone the cron is read in, an IANA name such as Asia/Kolkata.
- Limits
- 1 to 64 characters.
on"call"call: it runs whenever your system posts to its trigger_url.
- Type
"call"
filtersmap of anyWith on: call, what a call's payload must match for the routine to run.
- Type
map of any
timezonestringThe zone every is read in, an IANA name. Absent: each user's own (or your company's own Bash's), then UTC.
- Limits
- 1 to 64 characters.
for"us" | "each customer"requiredus: your company's own Bash. each customer: a copy for every user, made the first time they talk to Bash here.
- Type
"us" | "each customer"
enabledbooleanfalse keeps the routine but stops its runs. A routine for each user is on while it is in the file.
- Type
boolean
limitsobjectWhat one task may spend.
- Default
{"per_task_usd":2}
limits: { per_task_usd: 5 }per_task_usdnumberThe most one task may spend, in dollars: above 0, at most 100. Absent: 2.
- Default
2- Limits
- Above 0, at most 100.
testsobject[]Tests each new version runs before it is promoted. At most 20.
- Default
[]- Limits
- At most 20 items.
tests: - name: Bag allowance ask: "How many kilos can I take on booking TN-48213?" expect: Says 7 kg of cabin baggage. tool_results: { get_booking: { cabin_kg: 7 } }namestringIts name, which finds the test again on the next apply. Absent: the start of ask.
- Limits
- 1 to 120 characters.
askstringrequiredWhat the test user wants, in their words.
- Limits
- 1 to 2000 characters.
expectstring | string[]requiredWhat a pass looks like: one line, or up to 12.
- Type
string | string[]
neverstring | string[]What must never happen: one line, or up to 12.
- Type
string | string[]
personastringWho the test user is. Absent: a person who uses the company's app.
- Limits
- 1 to 2000 characters.
tool_resultsmap of anyWhat each tool answers in this test: a function tool by its name, and a tool of an MCP server as <server>.<tool> (the server's slug, from its URL's host), since a test never runs one for real unless the server marks it read-only. A tool with none answers an error.
- Type
map of any
approvesbooleantrue: the test user says yes to each approval for a tool of your MCP server, which plays its tool_results entry or does not run, so the test can check what Bash does after a yes. Absent or false: it says no to every approval. Anything else that waits for a yes is always declined.
- Type
boolean
webhooksmap of (string | "*")[]Where events go: each https URL, with the events it gets, or * for every one.
- Default
{}
webhooks: "https://example.com/vestra": - task.completed - interaction.created