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

# Data

> The facts your world is built from

`data/` holds the raw facts of your world: ids, names, quantities, prices, statuses, dates. One JSON file per collection, named after it.

```
data/
├── accounts.json
├── contacts.json
├── leads.json
├── opportunities.json
├── stages.json
└── users.json
```

Nothing in here is code, and nothing in here is computed.

## Facts only, never derived values

**If a number can be computed from other fields, do not store it.**

ERP's datasets hold quantities and unit prices. `lineTotal`, `subtotal`, `taxAmount` and `totalAmount` never appear in `data/` — they are derived when the world is built. CRM's `stages.json` stores a probability per stage; no opportunity stores its own weighted value.

Two reasons, and the second is the one that bites:

1. **A stored total goes stale.** Edit a quantity in a dataset and the total beside it is now wrong, with nothing to catch it.
2. **A verifier reading a stored total is grading its own copy of the answer.** The whole point of deterministic verification is that expected values are derived from the world, not read out of it. Store the answer in the data and the check becomes circular.

```json opportunities.json theme={null}
{
  "id": "OPP-001",
  "amount": { "amount": 120000, "currency": "USD" },
  "stageId": "STG-003"
}
```

The weighted value of this opportunity is `amount × the probability on STG-003`. It lives nowhere on disk — it is computed on read, because the agent can move the opportunity to another stage mid-rollout.

<Note>
  Where derived values belong depends on whether they can change during a run. See [State](/silo/environments/state) for the distinction between deriving once at load and exposing a helper.
</Note>

## Managing datasets

Data is the one part of an environment the CLI fully manages, because it is inert — a JSON file cannot become an agent capability.

```bash theme={null}
npx @burn0/silo data list --env demo
```

```
accounts        data/accounts.json       2435B
activities      data/activities.json     4553B
auditLog        data/auditLog.json          3B
contacts        data/contacts.json       3577B
leads           data/leads.json          5295B
opportunities   data/opportunities.json  7269B
sequences       data/sequences.json        81B
stages          data/stages.json          571B
users           data/users.json          1308B
```

| Command                          | Purpose                  |
| -------------------------------- | ------------------------ |
| `data list --env <env>`          | Every dataset, with size |
| `data show <name> --env <env>`   | Print one dataset        |
| `data add <name> --env <env>`    | Create a dataset         |
| `data update <name> --env <env>` | Replace one              |
| `data remove <name> --env <env>` | Delete one               |

`add` and `update` take the content either inline or from a file:

```bash theme={null}
npx @burn0/silo data add tickets --env demo --file ./seed/tickets.json
npx @burn0/silo data add regions --env demo --data '[{"id":"EU","name":"Europe"}]'
```

Add `--json` to any of them for machine-readable output.

## How data becomes a world

`environment.ts` imports the datasets, assembles them, and derives whatever is computed at load:

```typescript environment.ts theme={null}
import accountsData from "./data/accounts.json" with { type: "json" };
import usersData from "./data/users.json" with { type: "json" };

export const SIMULATION_NOW = "2026-03-16";

export function createState(): State {
  return structuredClone({
    now: SIMULATION_NOW,
    users: indexById(usersData as User[]),
    accounts: indexById(accountsData as Account[]),
    // ...
  });
}
```

Two details matter here.

**`indexById`** turns a JSON array into a `Record<string, T>` keyed by id, which is how tools look rows up without scanning.

**`structuredClone`** is not optional. Node caches imported JSON modules for the life of the process, so without the clone the second rollout in a `--runs 5` sweep starts from whatever the first one left behind.

## Seeding realistically

Datasets are the input to every task and every verifier, so their shape decides what your environment can actually test.

* **Give tasks a unique answer.** If two reps tie for "most stalled deals", the task is ambiguous and the verifier cannot grade it. CRM's seed data is arranged so each question has exactly one correct answer.
* **Include the awkward rows.** A deactivated user who still owns open work, an invoice that does not match its purchase order, a lead already converted. Agents fail on edge cases, which is what you want to measure.
* **Keep ids stable and readable.** `USR-004`, `OPP-012`, `VINV-103`. They appear in task instructions, verifier code, traces and diffs.
