Volter World

Shape the World for a test

Build one repeatable workflow with stored data, a scripted answer, a one-time failure, an explicit retry and a frozen clock. Use Node 22.6 or newer and npm in an empty directory; no platform account or real key is needed.

Separate records from behavior

Create stored records through the vendor's own API. Use ordered scenario handlers for model judgment, stateless lookups and faults. A handler must never fake success for a stored mutation. This example creates a Stripe customer and asks OpenAI to classify its signup; the first ask fails, the second returns the authored label.

package.json
{
  "name": "acme-web",
  "private": true,
  "type": "module",
  "dependencies": {
    "stripe": "17.7.0",
    "openai": "4.104.0"
  },
  "devDependencies": {
    "@volter/world": "3.0.63",
    "@volter/twin-stripe": "3.0.1",
    "@volter/twin-openai": "3.0.1"
  }
}
.env.example
STRIPE_SECRET_KEY=
OPENAI_API_KEY=
workflow.mjs
import assert from 'node:assert/strict';
import Stripe from 'stripe';
import OpenAI from 'openai';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const model = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, maxRetries: 0 });
const customer = await stripe.customers.create({ email: 'retry@example.com' });
assert.equal(customer.created, Date.parse('2026-01-15T12:00:00Z') / 1000);
const ask = () => model.chat.completions.create({ model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'classify this signup' }] });
await assert.rejects(ask(), error => error.status === 429);
const answer = await ask();
assert.equal(answer.choices[0].message.content, 'billing');
assert.equal((await stripe.customers.retrieve(customer.id)).email, 'retry@example.com');
const scenario = await fetch(`${process.env.OPENAI_TWIN_URL}/twin/scenario`).then(r => r.json());
assert.match(JSON.stringify(scenario), /rate-limit-once/);
console.log('stored data, one refusal, retry answer and frozen timestamp passed');
npm install
npx volter world init --name repeatable-workflow --twins stripe,openai

Review the selected vendors and their exact service sources before booting. Save this handler after init, replacing the starter OpenAI scenario for this example:

.volter/handlers/openai.json
{
  "handlers": [
    {
      "id": "rate-limit-once",
      "on": {
        "userTextIncludes": "classify this signup"
      },
      "once": true,
      "fault": {
        "kind": "status",
        "status": 429,
        "message": "retry this request"
      }
    },
    {
      "id": "signup-answer",
      "on": {
        "userTextIncludes": "classify this signup"
      },
      "respond": {
        "text": "billing"
      }
    }
  ]
}

Handlers are first-match, in order. once consumes the first rule once during that twin process's lifetime; the second rule then answers the same prompt. The SDK has retries disabled so the app can assert the first failure and retry explicitly. Your own SDK retry policy can exercise the same failure, but may hide it from application code.

Wire the handler for this released runtime

The pinned runtime in this example may omit scenario wiring when a published twin contains no starter journey. Saving the file alone does not select it. This helper explicitly names the authored file in the init-generated service and retains its other settings:

configure-scenario.mjs
import { readFileSync, writeFileSync } from 'node:fs';
const path = '.volter/world.json';
const config = JSON.parse(readFileSync(path, 'utf8'));
const service = config.services.find(s => s.id === 'openai');
if (!service?.execution?.colocate) throw new Error('Expected the generated OpenAI service');
service.execution.colocate.scenarioPath = '.volter/handlers/openai.json';
writeFileSync(path, JSON.stringify(config, null, 2) + '\n');
node configure-scenario.mjs

Execute and inspect

npx volter world up
npx volter world clock set 2026-01-15T12:00:00Z
npx volter world run -- node workflow.mjs
stored data, one refusal, retry answer and frozen timestamp passed
npx volter world log
npx volter world clock advance 30d
npx volter world down

The customer is real stored state inside the twin. The answer is authored test behavior, not a claim about a model's judgment. /twin/scenario shows handler matches and misses; /twin documents this implementation's matcher and time grammar. Use recovery when a call misses.

Repeat from the same conditions

npx volter world up
npx volter world reset
npx volter world clock set 2026-01-15T12:00:00Z
npx volter world run -- node workflow.mjs
stored data, one refusal, retry answer and frozen timestamp passed
npx volter world down

down retains data; up resumes it. Reset clears this disposable branch's vendor state and reseeds; a restarted twin rearms the once-handler. Restore the clock explicitly before repeating. Editing the handler and restarting loads the new behavior. Reset is destructive to this branch's changes, so use a failure branch when you need to preserve them.

For shared setup, use seed and reset. The cookbook provides reusable workflows; browser testing connects these techniques to application sessions and rendered assertions.

View Markdown source

On this page