worldseq

TypeScript and Python SDKs

Install the player and operator clients and use their typed runtime contracts.

For an end-to-end isolated player example, see Harbor SDK agents.

The SDKs connect to an existing worldseq server. They contain public request/response contracts and HTTP clients; they do not contain the simulator, hidden company parameters, private instance seeds, reference policies, or judge implementation. Both clients validate requests and responses against the same generated JSON Schema. Python additionally returns strict Pydantic models. Server-side relational checks remain authoritative: JSON Schema cannot prove that an account, commitment or evidence reference belongs to an episode.

Install the release artifacts

From an extracted SDK release directory:

npm install ./worldseq-sdk-0.1.0.tgz
python -m pip install ./worldseq_sdk-0.1.0-py3-none-any.whl

The Python source distribution can also be installed with pip install ./worldseq_sdk-0.1.0.tar.gz. These commands install local artifacts; they do not assume publication to npm or PyPI. TypeScript supports ESM on Node 22/24 and Bun. Python supports 3.11–3.14. Consult the retained release smoke receipt for the interpreter versions and operating systems actually exercised for a particular release.

Player access

An operator gives a player an episode ID, its token, and the player server URL. Keep the control token with the operator. A player client cannot create, seal, import, or inspect another run through its interface; the server also checks token scope.

import { createPlayerClient, WorldseqError } from "@worldseq/sdk";
const player = createPlayerClient({
  baseUrl: process.env.WORLDSEQ_PLAYER_URL!,
  episodeId: process.env.WORLDSEQ_EPISODE_ID!,
  token: process.env.WORLDSEQ_EPISODE_TOKEN!,
  timeoutMs: 30_000,
});
const snapshot = await player.snapshot();
for await (const page of player.evidencePages({ limit: 50 })) {
  for (const observation of page.items) console.log(observation);
}
import os
from worldseq import PlayerClient, AsyncPlayerClient, WorldseqError

with PlayerClient(
    base_url=os.environ["WORLDSEQ_PLAYER_URL"],
    episode_id=os.environ["WORLDSEQ_EPISODE_ID"],
    token=os.environ["WORLDSEQ_EPISODE_TOKEN"],
    timeout=30,
) as player:
    snapshot = player.snapshot()
    for page in player.evidence_pages(limit=50):
        print(page.items)

AsyncPlayerClient has the same methods using await, async with, and async for. AsyncAdminClient is also available. Python accepts generated worldseq.models request models or dictionaries; unknown fields and wrong JSON types are rejected before sending. Responses expose wire field names such as requestKey and nextCursor; method arguments use Python conventions such as episode_id.

The player methods are snapshot, capabilities, evidence, decide, assess, and wait. Python and TypeScript return the server’s assessment receipt, not a post-assessment snapshot; fetch another snapshot to observe the accepted revision. wait can return before its requested day when new evidence interrupts the advance. Inspect the returned day before waiting again.

Operator access and lifecycle

Use createAdminClient({baseUrl, token}) or Python AdminClient(base_url=..., token=...) on the control server. It provides catalog, createEpisode/create_episode, seal, run, history, updates, evaluation, and rollouts. historyPages/history_pages follows opaque history cursors without rebuilding them. Evidence iterators preserve query filters and reject repeated/backward cursors. Other paginated methods expose the server’s cursor; pass it back unchanged.

Development creation is {mode: "development", taskId: "clearbeam.incident-week", seed: "local-example"}. Graded creation is {mode: "graded", instanceId, requestKey} and requires an operator-provisioned private instance. The SDK cannot mint a private instance or substitute a chosen graded seed. Reuse the original requestKey when resolving an uncertain graded creation.

Seal the episode through the operator client. Inspect valid, all constraints, and finalizationState/finalization together: a reconciled ledger alone does not establish success. A missing or inconclusive required counterfactual result must not be treated as eligible. Repeated seal calls use the same episode; they do not create another attempt.

Executable complete examples are sdks/typescript/examples/play.mjs and sdks/python/examples/play.py in the source distribution. They open a seven-day development episode, test idempotency and stale revisions, submit an uncertainty assessment, paginate observations, advance, seal, and inspect history. They are transport examples with an intentionally simple plan, not recommended task solutions. Set WORLDSEQ_CONTROL_URL, WORLDSEQ_PLAYER_URL, and WORLDSEQ_CONTROL_TOKEN privately before running them from a project with the SDK installed.

Errors, retries, and limits

Both clients expose WorldseqError.code, .status, and .ambiguous. The error text is a safe summary, not an untrusted server body. Examples include invalid_request, invalid_response, stale_revision, request_timeout (Python), request_aborted (TypeScript), and server-specific domain codes. Historical servers without a code produce request_rejected. Authentication headers are never forwarded through redirects.

Player calls handled by the episode runtime consume tool turns, including snapshot/evidence reads, rejected engine operations, and idempotent retries. Reusing a request key prevents duplicate business effects; it does not refund the new call. Evidence iterators issue one metered call per fetched page. The SDK issues no additional observation reads beyond the methods or iterators you invoke.

The local worldseq-agent-v1 step runner has additional explicit adapter overhead: it fetches capabilities once, then a snapshot and normally a default evidence page before each agent step, followed by the requested action. A previously requested evidence page replaces that step’s default evidence read. Those automatic reads count toward the same tool-call ceiling. Equivalent-call parity means the same explicit call sequence receives the same metering and grading; it does not mean one model step equals one HTTP/MCP call. See the agent protocol.

There are no automatic retries, including reads. A timeout or connection loss after a mutation may mean the server accepted it. Preserve the complete original payload, requestKey, and expectedRevision; retry that same request or inspect current state. Do not generate a fresh key or silently update the revision to hide a conflict. An exception with ambiguous=true explicitly calls out this uncertainty. Malformed, oversized, redirected, or server-error mutation responses also remain uncertain: rejecting the response does not prove the server rejected the action. A cancellation before TypeScript dispatch leaves ambiguous=false.

The default response cap is 8 MiB and the request cap is 128 KiB. Reduce page size if a response exceeds the cap, or explicitly raise maxResponseBytes/max_response_bytes when warranted. TypeScript supports per-call AbortSignal and wall-clock timeout. Python uses HTTPX connect/read/write/pool timeouts, supports per-call timeout overrides, and propagates asynchronous cancellation. Supplying your own HTTPX client transfers connection-pool/proxy configuration to you; the SDK does not close an externally supplied client. Default HTTPX clients ignore environment proxy credentials.

Contract generation and verification

From the source distribution:

bun run sdk:generate
bun run contracts:check
bun run sdk:test:typescript
bun run sdk:test:python
bun run sdk:build

Generation uses an explicit whitelist for the only accepted public action-term transform and fails on unknown transforms. Generated TypeScript/Pydantic files are intentionally larger than hand-written modules; do not edit them manually. The published SDKs include contract-version.json and the exact JSON schemas. Backend additions require regeneration and conformance tests before packaging. contracts:check checks the exported server schema; release packaging also checks the SDK schema/version copies. Installed-artifact tests run independently of the monorepo’s module resolution.

Free plans and metered products

Read snapshot.business.usageBilling when present. Its public tariff uses exact integer centsPerBlock and unitsPerBlock, alongside freeUnitsPerCalendarMonth and any monthly spend limit. For example, 2 cents per 3 units is a rational tariff, not a floating-point dollar price. Send and retain canonical integer cents and unit counts; do not replace the meter’s cumulative charge with independently rounded per-request prices. The server applies quota, authorization, service and calendar-month rules.

Free-plan membership, payment authorization, billable usage, earned revenue and cash collection are different quantities. Use the published membership/meter counts and earnedCents, variableCostCents, collectedCents and receivableCents. Individual customer records and the internal free status are not exposed by these clients. A growth study with outcome: "usage_contribution" reports freeSignups and authorizedAccounts separately from collected cash and realized contribution.

Always obtain the episode’s capabilities(). A metered company does not offer the legacy pricing_change, onboarding_improvement or reliability_improvement operations; an operation’s presence in the shared request type is not permission to use it in every company. Tariffs are the supplied immutable terms unless an actual operation is offered. Where a service window includes productId, preserve it: core_units can refer to that metered product, while addon_accesses refers to an actual addon. Do not pool unrelated products to calculate service eligibility.

Both clients accept day 730 in wait, and a wait may return earlier because new evidence interrupts advancement. Inspect the returned day and remaining budgets. Every snapshot/evidence/capability call still consumes a gameplay call; pagination and additional observations are not silently free. The standard 128-decision and 1,024-call limits still apply to two-year tasks.