Quickstart
Run an agent inside a living world.
Create a commerce world, give your agent production-shaped access, advance thirty simulated days and evaluate the state it leaves behind.
Prerequisites
- Node.js 20 or later.
- A server-side Counterworld project key.
- An agent harness that can accept an API base URL and scoped token.
Install and authenticate
The control SDK creates and operates worlds. Your agent does not need to import it.
npm install @counterworld/sdk
export COUNTERWORLD_API_KEY=sc_live_...
Create a populated world
Start from maintained Shopify and Stripe shapes. Counterworld creates coherent history before the agent enters and keeps simulated buyers active afterward.
import {
Counterworld,
catalog,
buyers,
storeAdmins,
warehouseOperators,
} from "@counterworld/sdk";
import { runAgent, runChallengerAgent } from "./agents";
const counterworld = new Counterworld({
apiKey: process.env.COUNTERWORLD_API_KEY,
});
const world = await counterworld.worlds.create({
name: "spring-sale",
systems: [
catalog.shopify(),
catalog.stripe(),
],
history: { years: 2, seed: "retail-042" },
population: [
buyers({
count: 12_000,
discountSensitivity: 0.65,
returnPropensity: 0.18,
}),
storeAdmins({ count: 24, approvalDelayHours: 6 }),
warehouseOperators({ count: 80, shiftCoverage: 0.82 }),
],
clock: { startAt: "2026-03-01T09:00:00Z" },
});
const start = await world.checkpoints.create({
name: "before-agent",
});
Connect the agent through the native interface
Issue scoped credentials for the world. Give the endpoint and token to the same agent harness you use against production or staging.
const shopify = await world.interfaces.connect("shopify-admin", {
scopes: ["read_orders", "write_discounts", "write_refunds"],
});
await runAgent({
task: "Run retention operations through the spring sale.",
shopifyBaseUrl: shopify.baseUrl,
shopifyAccessToken: shopify.accessToken,
});
Smoke-test the same interface
const response = await fetch(
`${shopify.baseUrl}/admin/api/2026-01/orders.json?limit=5`,
{
headers: {
"X-Shopify-Access-Token": shopify.accessToken,
},
},
);
if (!response.ok) throw new Error(await response.text());
console.log((await response.json()).orders.length);
The agent sees Shopify-shaped resources and behavior. Counterworld’s clock, privileged state and evaluation controls remain outside the agent boundary.
Advance the world
Move time forward while simulated buyers, store admins, warehouse operators and scheduled events continue reacting to the agent’s changes.
await world.clock.advance({
days: 30,
mode: "until-idle",
});
const day30 = await world.checkpoints.create({
name: "day-30",
});
Fork and evaluate the outcome
Fork the starting checkpoint, run a challenger for the same thirty days and compare the resulting worlds.
const challenger = await world.forks.create({
from: start.id,
name: "challenger-policy",
});
const access = await challenger.interfaces.connect("shopify-admin", {
scopes: ["read_orders", "write_discounts", "write_refunds"],
});
await runChallengerAgent({
task: "Run retention operations through the spring sale.",
shopifyBaseUrl: access.baseUrl,
shopifyAccessToken: access.accessToken,
});
await challenger.clock.advance({ days: 30, mode: "until-idle" });
const candidateDay30 = await challenger.checkpoints.create({
name: "day-30",
});
const evaluators = {
metrics: ["gross_margin", "repeat_purchase_rate", "refund_rate"],
invariants: ["no_negative_inventory", "refunds_match_ledger"],
};
const [baseline, candidate] = await Promise.all([
world.evaluate(evaluators),
challenger.evaluate(evaluators),
]);
const diff = await world.inspect.diff({
from: day30.id,
to: candidateDay30.id,
});
console.log(baseline.metrics);
console.log(candidate.metrics);
console.log(diff.summary);
Example report
{
"baseline": { "gross_margin": 0.402, "repeat_purchase_rate": 0.251 },
"candidate": { "gross_margin": 0.418, "repeat_purchase_rate": 0.274 },
"delta": { "gross_margin": 0.016, "repeat_purchase_rate": 0.023 },
"violations": { "baseline": 0, "candidate": 0 }
}
Clean up
Destroy disposable worlds when the run is complete. Checkpoints and exported reports remain available according to project retention settings.
await challenger.destroy();
await world.destroy();
Where to go next
- Core concepts explains definitions, instances, events and checkpoints.
- Worlds covers catalog, imported and custom system definitions.
- TypeScript SDK documents methods, inputs, return types and errors.