> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beta.b3os.org/llms.txt
> Use this file to discover all available pages before exploring further.

# b3os.yaml (design preview)

A design for declaring the models, packs, sandboxes, browser pools, routines and external services a repository's agents use. Nothing applies it yet.

This page describes a design, not a feature. No B3OS service reads `b3os.yaml`, and there is no apply: the two CLI commands below only check the file and print what an apply would do. They are not in a published CLI release yet. Version 0 of the format can change or be dropped without notice.

A repository that runs agents on B3OS uses several building blocks at once: a model, a few packs and their connections, sandboxes of a given size, browsers, the routines that tie them together, and services B3OS does not run, such as a database. Today each one is set up by its own API call or CLI command. `b3os.yaml` is a design for writing all of it down in one file in the repository, so a reviewer can read the architecture and a tool can compare it with what the project holds.

## What the file declares

| Block | What an entry names | What the dry run checks, and where it reads |
|---|---|---|
| `infer.models` | a model ID, its kind, the capabilities the code relies on (`tools`, `json_schema`, `image_input`) and the smallest context it works with | that the node serves the model with those capabilities (`GET /v1/infer/models`) |
| `actions.packs` | a pack, optionally an exact version, and which stored connection each of its connection keys uses | that the version is on the node and that every connection key has a stored connection (`GET /v1/actions/packs/{namespace}/{name}`, `GET /v1/vault/connections`) |
| `sandboxes` | a sandbox shape: template, size, ports | that the template exists, the size is within your limits, and whether it is a size the node keeps started (`GET /v1/sandboxes/templates`, `GET /v1/limits`) |
| `vision.pools`, `render.pools` | how many browsers to keep started, and a saved profile | the profile, for vision (`GET /v1/vision/profiles`); pool sizes are not declarable in the beta |
| `routines` | a routine definition file in the repository | that it compiles (`POST /v1/routines/validate`), and whether the routine is new, changed or unchanged against its active version (`GET /v1/routines/{routine}`) |
| `resources` | a service B3OS does not run (`postgres`, `mysql`, `redis`, `vector`, `object_store`, `http`), its hosts, the vault connection that holds its credential, and which routines and sandboxes use it | that the connection is stored (`GET /v1/vault/connections`) |

The beta has no API object for a sandbox shape: your code creates sandboxes when it needs them. A `sandboxes` entry records the shape the code asks for, so the dry run can check it and a reader can see it.

## An example

The sample declares a weekday market brief: a routine reads a page, summarizes it with the node's model and posts it to Slack, a sandbox draws charts, and the briefs go to a Postgres database.

```yaml b3os.yaml
version: 0
name: market-brief
description: Each weekday morning, read a markets page, summarize it with the node's model, post it to Slack and
  keep a copy in Postgres.

infer:
  models:
    - id: b3os/default
      kind: chat
      needs: [tools, json_schema]

actions:
  packs:
    - id: io.b3os/slack
      connections:
        token: slack-bot # the label of a stored vault connection

sandboxes:
  - name: charts
    template: code-interpreter
    vcpu: 2
    memory_mib: 2048
    ports: [8000]
    warm: 1

vision:
  pools:
    - name: readers
      browsers: 2

routines:
  - file: routines/brief.yaml

resources:
  - name: briefs-db
    kind: postgres
    connection: briefs-db
    hosts: [db.example.com:5432]
    used_by: [routine/market-brief, sandbox/charts]
```

`routines/brief.yaml` is an ordinary [routine definition](/routines); its `name` is the routine's name. The file is the one `b3os routine deploy` takes today.

## Check the file

```bash
b3os manifest validate            # ./b3os.yaml
b3os manifest validate path/to/b3os.yaml --json
b3os manifest schema              # the JSON Schema
```

`validate` works offline. It checks the file against the JSON Schema and reports each finding with its line and column, then checks what a schema cannot: names declared twice, routine files that are missing or do not parse, `used_by` entries that name nothing declared, and packs or models a routine calls that the file does not declare (a warning). It exits 0 when the file is valid and 5 when it is not.

## Print the plan

```bash
b3os apply --dry-run              # ./b3os.yaml
b3os apply --dry-run -f path/to/b3os.yaml --json
```

The dry run reads the project the key belongs to and prints one line per declared item:

| Mark | Meaning |
|---|---|
| `+` | an apply would create it (a routine that does not exist yet) |
| `~` | an apply would change it (a routine whose definition differs from its active version; the changed fields are listed) |
| `=` | it is in place, or there is nothing to apply (models, packs, sandbox shapes, external services whose credential is stored) |
| `?` | not declarable in the beta (warm sandbox and browser pool sizes) |
| `!` | a problem an apply would hit (a model the node does not serve, a missing or expired connection, a routine that does not compile) |
| `-` | not checked, or only partly: the key may not read it, or one of the item's reads (its connections, limits, profile or compile) answered 403, and the line says which |

A pack connection key the file leaves out is checked the way a routine step resolves it: the project's newest connection for that pack and key without a `subject`. An end user's connection (one with a `subject`) counts only when the file names it, so a key with nothing else stored is a problem ([Call actions](/actions/call#connections)). A key whose scopes include `*` or `routines:*` can publish a routine; the plan says so when the key cannot.

It only reads. Every request is a `GET`, except `POST /v1/routines/validate`, which compiles a definition and stores nothing. It exits 5 when the plan has a problem or an unchecked item and 0 when it has neither; an API error, such as a key that is not valid, exits with the CLI's usual code. `b3os apply` without `--dry-run` stops with a usage error and sends nothing.

This is the dry run of the example above against `beta-api.b3os.org`, recorded on 2026-11-06 at 01:43 UTC with a project key from a source checkout of the CLI. The project stores neither connection the file names, so the plan has two problems and the command exited 5:

```text b3os apply --dry-run
b3os.yaml v0 design preview: dry run of market-brief (examples/b3os-yaml/market-brief/b3os.yaml) against https://beta-api.b3os.org, project prj_01m69ww39f6nq8w30vh3xkmsh8
Nothing was created or changed.

infer
  = b3os/default   served: chat (alias of b3os/qwen3.5-9b), context 32768 tokens, tools, json_schema, image_input

actions
  ! io.b3os/slack  1.0.0 (latest) on the node, 27 actions; packs need no install step
                   connection token: no stored io.b3os/slack connection labelled slack-bot

sandboxes
  = charts         code-interpreter, 2 vCPU, 2048 MiB, 4 GiB; created by your code at run time, nothing to apply
                   a size this node keeps started: a create claims a waiting microVM
  ? charts warm    warm: 1 is not declarable in this beta; the node sizes its warm pools

vision
  ? readers        2 browsers is not declarable in this beta; the node sizes its browser pools

routines
  + market-brief   new routine from routines/brief.yaml, version 1
                   compiles: 3 steps

resources
  ! briefs-db      external postgres: B3OS does not run it (db.example.com:5432)
                   connection briefs-db: not stored in this project
                   sandbox/charts would get the credential as a sandbox secret from the connection

Plan: 1 to create, 2 in place, 2 not declarable yet, 2 problems.
+ create  ~ update  = in place  ? not declarable in this beta  ! problem  - not checked
```

## What version 0 leaves out

- **Apply.** Nothing creates, publishes or deletes from the file. The design question that blocks it is ownership: which objects a file owns, so that removing an entry can remove the object without touching ones created by hand.
- **Pools.** Warm sandbox and browser pool sizes are set by the node in the beta. The fields exist so a file can say what it needs.
- **Secrets.** The file names stored connections by ID or label and never holds a credential.
- **Environments.** A file describes one project; version 0 has no per-environment overrides.
- **Builds.** Custom sandbox templates do not exist in the beta, so a sandbox entry names one of the node's templates.