# Seed and reset

Give your app known starting records, then return to them after a run. This example uses Stripe's
real SDK with a local twin. Use Node 22.6 or newer and npm in an empty directory; installation
needs registry access. No platform account or real Stripe key is needed.

## Make the World

Save these files in the empty app directory:

```json file=package.json
{
  "name": "seed-app",
  "private": true,
  "type": "module",
  "dependencies": { "stripe": "17.7.0" },
  "devDependencies": {
    "@volter/world": "3.0.63",
    "@volter/twin-stripe": "3.0.1"
  }
}
```

```text file=.env.example
STRIPE_SECRET_KEY=
```

```bash
npm install
npx volter world init --name seed-app
```

Review Stripe and its exact package/version before keeping the selection. A twin may ship
starting data, but a published package need not include a seed script. Inspect the generated
files rather than assuming `init` created a story for every implementation.

## Author the starting data

For this fresh example, save `.volter/seed.ts`. In an existing project, retain its seed entry and
add your story to it; do not replace a team's defaults.

```ts file=.volter/seed.ts
import { World } from '@volter/world';
import Stripe from 'stripe';

World.open({ root: process.cwd() }).setClock('2026-01-15T12:00:00Z');
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const existing = await stripe.customers.list({ email: 'founder@example.com' });
if (existing.data.length === 0) {
  await stripe.customers.create({ email: 'founder@example.com', name: 'Grace' });
}
```

Stored records go through the vendor API, so a rejected creation fails the seed. This seed
looks before creating and sets the clock before its first vendor write. Running it twice
therefore keeps one founder instead of creating a duplicate. Commit the seed with the World
config, package manifest and lockfile; keep running state ignored.

Save `check-story.mjs` to assert the starting state:

```js file=check-story.mjs
import assert from 'node:assert/strict';
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const founders = await stripe.customers.list({ email: 'founder@example.com' });
assert.equal(founders.data.length, 1);
assert.equal(founders.data[0].name, 'Grace');
assert.equal(founders.data[0].created, Date.parse('2026-01-15T12:00:00Z') / 1000);
assert.equal((await stripe.customers.list({ email: 'ada@example.com' })).data.length, 0);
console.log('one founder, frozen timestamp and no app customer');
```

## Load and check

A fresh branch's first startup runs its seed. A later ordinary startup resumes stored state;
it does not reload the seed just because you stopped yesterday.

```bash
npx volter world up
npx volter world run -- node check-story.mjs
```

```text
one founder, frozen timestamp and no app customer
```

Seeded records are starting data, separate from the app's pending writes:

```bash
npx volter world log
```

```text
(no changes yet)
```

Explicit seeding uses the same entry. Check the result instead of assuming the seed is idempotent:

```bash
npx volter world seed
npx volter world run -- node check-story.mjs
```

```text
one founder, frozen timestamp and no app customer
```

## Let the app write

Save `signup.mjs`:

```js file=signup.mjs
import assert from 'node:assert/strict';
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const customer = await stripe.customers.create({ email: 'ada@example.com', name: 'Ada' });
assert.equal((await stripe.customers.retrieve(customer.id)).email, 'ada@example.com');
console.log('app customer created and read back');
```

```bash
npx volter world run -- node signup.mjs
npx volter world log
```

```text
customer.create
```

## Reset deliberately

Use this example's disposable branch. Reset discards its changes, boots again and loads the
seed. Here the seed also restores the clock; a different project's reset alone need not freeze it.

```bash
npx volter world reset
npx volter world run -- node check-story.mjs
```

```text
one founder, frozen timestamp and no app customer
```

```bash
npx volter world log
```

```text
(no changes yet)
```

Grace is back and Ada is absent. A parent with dependent branches refuses reset: a child
references its history, rather than making an independent backup. [Branch lifetime](../concepts/the-model.md#a-branch-is-a-position-not-a-copy)
explains the refusal. Ordinary `down` can still stop compute while retaining history.

```bash
npx volter world down
```

Resume with `up` to keep the state. Use [resume a World](./resume-a-world.md) for daily work.
Seeding creates records; [scenarios](./shape-the-world-for-a-test.md) script answers and faults.
A handler must never fake a successful stored mutation.

## Make browser states in the seed

Vendor browser state is a separate input. The World's named-browser helper can add cookies,
local storage and context settings through requests to a twin's own sign-in flow. The project
must install `@volter/world-core` to import `@volter/world-core/browser`; a global CLI does not
supply that dependency to a project seed.

The [browser state API](../reference/http-api.md#browsers) owns names, limits and loading local
or hosted profiles. Seeded vendor browser profiles are outside the log, diff, changesets and
push. Branches inherit them; reset reloads the profiles created by the seed. Your application's
own sessions, database and browser state still need their own setup:
[test an app in the browser](./test-in-the-browser.md) shows a complete application example.

## Load a named browser locally

Local exports live in the World state directory at `.volter/browsers/<name>.json`. The document
contains `context` and `storageState`. Load both, together with the World's proxy and CA settings,
when configuring your browser runner; [run a full stack](./run-a-full-stack.md) explains the
application setup. For a served World, read the named profile through the
[browser state API](../reference/http-api.md#browsers). These are vendor sessions; they do not
automatically sign a person into your application.

<!-- Fenced tutorial executor: packages/cli/src/journeys/tutorial.ts. Execution scope is recorded separately. -->
