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.
{
"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"
}
}STRIPE_SECRET_KEY=
OPENAI_API_KEY=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: '[email protected]' });
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, '[email protected]');
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,openaiReview the selected vendors and their exact service sources before booting. Save this handler after init, replacing the starter OpenAI scenario for this example:
{
"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:
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.mjsExecute and inspect
npx volter world up
npx volter world clock set 2026-01-15T12:00:00Z
npx volter world run -- node workflow.mjsstored data, one refusal, retry answer and frozen timestamp passednpx volter world log
npx volter world clock advance 30d
npx volter world downThe 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.mjsstored data, one refusal, retry answer and frozen timestamp passednpx volter world downdown 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.