Use a catalog twin
Take an exact catalog release into a local World and run the vendor's real SDK against it. This example uses Tavily search and extraction. Search returns synthetic stored pages; generated answer text is a labeled stub. It does not search the public web or evaluate answer quality.
Use Node 22.6 or newer and npm. No Tavily account, real API key or platform login is needed. Installation needs registry access. Start in an empty directory and save the files below.
Install the selected release
Choose a twin explains publishers, measurements and defaults. This example
selects @volter/twin-tavily@1.0.1 from catalog snapshot 0.2.3.
Save package.json:
{
"name": "search-app",
"private": true,
"type": "module",
"dependencies": { "@tavily/core": "0.7.13" },
"devDependencies": {
"@volter/world": "3.0.63",
"@volter/twin-tavily": "1.0.1"
}
}Save .env.example with an empty value:
TAVILY_API_KEY=npm install
npx volter world init --name search-apptavily
COVERED:Review the detected vendor. Inspect .volter/world.json: its service should name the selected
package and version. Commit the config and lockfile. The catalog supplies discovery; the World
config records which implementation this app runs.
Supply a synthetic page
Tavily searches public web content in production. This local example supplies its page content.
The twin's /_twin/pages fixture API is explicitly twin-specific, not a Tavily production API.
It creates stored data; a response handler must not pretend to create it.
Save seed-page.mjs:
import assert from 'node:assert/strict';
const response = await fetch(`${process.env.TAVILY_TWIN_URL}/_twin/pages`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
url: 'https://schedule.example/yoga',
title: 'Yoga schedule',
content: 'Yoga starts Tuesday at 18:00.'
})
});
assert.equal(response.status, 201);
console.log('synthetic page created');npx volter world up
npx volter world clock set 2026-01-15T12:00:00Z
npx volter world run -- node seed-page.mjssynthetic page createdThe fixture is stored locally. The .example URL names the synthetic record; nothing fetches
a real page at that address.
Run the real SDK
Save search.mjs. It uses the SDK's normal destination and the World's throwaway credential:
import assert from 'node:assert/strict';
import { tavily } from '@tavily/core';
const client = tavily({ apiKey: process.env.TAVILY_API_KEY });
const found = await client.search('yoga schedule', {
maxResults: 3, includeAnswer: true, includeRawContent: 'text'
});
assert.equal(found.results[0].url, 'https://schedule.example/yoga');
assert.match(found.results[0].rawContent, /Tuesday at 18:00/);
assert.match(found.answer, /\[twin-stub\]/);
const extracted = await client.extract([
'https://schedule.example/yoga', 'https://missing.example/page'
]);
assert.equal(extracted.results[0].url, 'https://schedule.example/yoga');
assert.match(extracted.results[0].rawContent, /Tuesday at 18:00/);
assert.equal(extracted.failedResults[0].url, 'https://missing.example/page');
console.log('search, extraction and missing-page checks passed');npx volter world run -- node search.mjssearch, extraction and missing-page checks passedThese assertions check finding the fixture, reading its content and handling an absent page. They do not establish real search ranking, generated answer quality or support for every operation.
Inspect, repeat and stop
npx volter world log
npx volter world statusThe log shows recorded state effects, rather than a transcript of every read. For the dashboard, see inspect a World.
Reset removes the run's state. Recreate the page and freeze the same clock before repeating:
npx volter world reset
npx volter world clock set 2026-01-15T12:00:00Z
npx volter world run -- node seed-page.mjs
npx volter world run -- node search.mjs
npx volter world downsearch, extraction and missing-page checks passed
Stopped search-appSeed and reset puts starting data in a project-owned seed. Shape the World for a test scripts stateless answers and faults. Update a twin covers changing the selected release deliberately.