# vestra.yaml reference

> 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](https://vestra.ai/developers/guides/travel-help-desk.md) 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
# yaml-language-server: $schema=https://vestra.ai/developers/vestra.schema.json

name: travel-help
instructions: |-
  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: auto
model: default
tools:
  - 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: true
approvals:
  - payment
  - booking
  - cancellation
limits:
  per_task_usd: 2
tests:
  - 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 Shah
```

## Fields

- `name` (`string`, required): The deployment's name, as in `PUT /v1/deployments/{name}`: lowercase letters, digits and dashes.
  ```yaml
  name: trip-rescue
  ```
- `instructions` (`string`): What Bash does here, and how, in plain words: up to 8,000 characters. Default: empty. Limits: at most 8000 characters.
  ```yaml
  instructions: You help Tripnest travellers fix broken trips. Always offer two options.
  ```
- `language` (`string`): The 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.
  ```yaml
  language: hi
  ```
- `model` (`string`): `default`, or a model id from `GET /v1/models`. Default: `default`. Limits: 1 to 100 characters.
  ```yaml
  model: default
  ```
- `apps` (`"all" | string[]`): The apps its users may connect: `all`, or a list. Default: `all`.
  ```yaml
  apps: [gmail, google-calendar]
  ```
- `tools` (`object[]`): Tools Bash may call: MCP servers by their URL, and functions your own code answers. At most 50. Default: `[]`. Limits: at most 50 items.
  ```yaml
  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.
    - `mcp` (`string (URL)`, required): The 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.
    - `name` (`string`): How the server is shown. Absent: the URL's host. Limits: 1 to 80 characters.
    - `auth` (`string`): One company secret, written `${NAME}`: sent as `Authorization: Bearer` and its value.
    - `headers` (`map of string`): Other headers to send. A value may carry `${NAME}` (a company secret) or `${user_secret:NAME}` (each user's own).
    - `deny` (`string[]`): 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_approval` (`string[]`): 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_asking` (`string[]`): 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.
    - `function` (`string`, required): The tool's name: lowercase letters, digits and underscores, starting with a letter.
    - `description` (`string`, required): What the tool does, so Bash knows when to call it. Limits: 1 to 1024 characters.
    - `input` (`map of any`): Its arguments: shorthand such as `{ pnr: string }`, with `[]` for a list and `?` for optional, or JSON Schema. Default: `{}`.
    - `timeout_s` (`integer`): Seconds Bash waits for your answer, 5 to 600. Absent: 120. Limits: 5 to 600.
    - `read_only` (`boolean`): true when the tool changes nothing, such as a lookup: Bash calls it without waiting for the person's yes. Absent: false, so it waits.
    - `run_without_asking` (`boolean`): true when the tool changes something that needs no yes: Bash calls it without waiting for the person's yes. Absent: false, so it waits.
- `skills` (`string | (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.
  ```yaml
  skills: ["./skills/refunds", { name: pdf }]
  ```
  - Either: A company skill, by its id.
    - `id` (`string`, required): A company skill's `skl_` id.
  - Or: A skill Bash already has, by its name.
    - `name` (`string`, required): The skill's name.
- `knowledge` (`string | (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.
  ```yaml
  knowledge: "./policies"
  ```
  - `notebook` (`string`, required): The notebook's `nb_` id.
- `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.
  ```yaml
  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.
  ```yaml
  memory: vestra
  ```
- `computer` (`object`): Bash's computer, ready before the first task: a setup script, repositories, environment variables and files.
  ```yaml
  computer:
    setup: "./setup.sh"
    env: { REGION: ap-south-1 }
  ```
  - `setup` (`string`): A 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.
    - `url` (`string`, required): The repository's address. Limits: 1 to 2048 characters.
    - `ref` (`string`): The branch, tag or commit. Absent: main. Limits: 1 to 200 characters.
    - `path` (`string`): The folder to clone into. Absent: the repository's name. Limits: 1 to 200 characters.
    - `token` (`string`): A token kept as a company secret, written `${NAME}`: never the raw value.
  - `env` (`map of string`): Environment variables. A credential is `${NAME}`, never a raw value.
  - `files` (`object[]`): Files uploaded with `POST /v1/files`, placed on the computer. Limits: at most 50 items.
    - `file_id` (`string`, required): The file's `file_` id.
    - `path` (`string`, required): Where it goes on the computer. Limits: 1 to 200 characters.
- `browser` (`object`): The 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.
  ```yaml
  browser:
    allowed_domains: [ixigo.com]
    blocked_paths: [ixigo.com/payments/]
  ```
  - `allowed_domains` (`string[]`): 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_paths` (`string[]`): 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.
- `routines` (`object[]`): 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.
  ```yaml
  routines:
    - ask: Check today's trips for delays
      every: "weekday at 08:00"
      for: each customer
  ```
  - `name` (`string`): Its name, which finds the routine again on the next apply. Absent: the start of `ask`. Limits: 1 to 200 characters.
  - `ask` (`string`, required): What Bash does on each run, in plain words. Limits: 1 to 8000 characters.
  - `every` (`string`): When 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.
  - `schedule` (`object`): When it runs, as cron.
    - `cron` (`string`, required): A cron expression: `0 7 * * *` runs at 7:00 every day. Limits: 1 to 120 characters.
    - `timezone` (`string`): The 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`.
  - `filters` (`map of any`): With `on: call`, what a call's payload must match for the routine to run.
  - `timezone` (`string`): The 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"`, required): `us`: your company's own Bash. `each customer`: a copy for every user, made the first time they talk to Bash here.
  - `enabled` (`boolean`): false keeps the routine but stops its runs. A routine for each user is on while it is in the file.
- `limits` (`object`): What one task may spend. Default: `{"per_task_usd":2}`.
  ```yaml
  limits: { per_task_usd: 5 }
  ```
  - `per_task_usd` (`number`): The most one task may spend, in dollars: above 0, at most 100. Absent: 2. Default: `2`. Limits: above 0, at most 100.
- `tests` (`object[]`): Tests each new version runs before it is promoted. At most 20. Default: `[]`. Limits: at most 20 items.
  ```yaml
  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 } }
  ```
  - `name` (`string`): Its name, which finds the test again on the next apply. Absent: the start of `ask`. Limits: 1 to 120 characters.
  - `ask` (`string`, required): What the test user wants, in their words. Limits: 1 to 2000 characters.
  - `expect` (`string | string[]`, required): What a pass looks like: one line, or up to 12.
  - `never` (`string | string[]`): What must never happen: one line, or up to 12.
  - `persona` (`string`): Who the test user is. Absent: a person who uses the company's app. Limits: 1 to 2000 characters.
  - `tool_results` (`map of any`): What 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.
  - `approves` (`boolean`): true: 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.
- `webhooks` (`map of (string | "*")[]`): Where events go: each https URL, with the events it gets, or `*` for every one. Default: `{}`.
  ```yaml
  webhooks:
    "https://example.com/vestra":
      - task.completed
      - interaction.created
  ```
