worldseq

Harbor SDK agent examples

Install and run the TypeScript or Python example inside Harbor’s isolated player container.

The source package’s examples/harbor/ directory contains two runnable deterministic custom agents using worldseq’s TypeScript and Python player SDKs. They read /public/session.json, inspect public capabilities and evidence, submit one idempotent no-op decision twice, and advance to the deadline. They make no model calls and need no model subscription or API key.

These are transport, isolation, retry and verification examples. They submit supported assessment payloads when available and can finish valid but ineligible. Use your own strategy to evaluate business performance. A release receipt applies only to the exact artifacts it names; an edited checkout does not inherit its result.

Requirements and directories

Install the simulator with Getting started, and read the Harbor operator guide for export and credential boundaries. You need:

  • Bun 1.3.14 and the 0.1.0 TypeScript and Python SDK archives from your selected release.
  • Harbor 0.24.0, a working Docker daemon, and Python 3.12 or newer on the Harbor host.
  • The simulator’s pinned player image with its network isolation retained.

The host Python and player Python are separate environments. The player image installs its interpreter at build time. Record actual runtime versions in the run receipt. Static checks below also use uv and the simulator source installation’s development tooling.

Set these paths to your actual installations. WORLDSEQ_RELEASE is the output directory from bun run release:package, or an extracted release bundle containing sdks/. COMPANION is the runnable example directory, not this documentation directory:

export WORLDSEQ_APP=/absolute/path/to/installed-world-sequencer
export WORLDSEQ_RELEASE=/absolute/path/to/world-sequencer-release
export COMPANION="$WORLDSEQ_APP/examples/harbor"

For a locally built package, run this from its matching simulator source and build runtime:

cd "$WORLDSEQ_APP"
bun run release:handoff --out "$WORLDSEQ_RELEASE"

This checks handoff.json, source identities and actual distribution bytes. A separately assembled bundle may also supply SHA256SUMS; verify it against the publisher’s trusted receipt before copying files. Checksums alone do not establish who produced a package.

Select and install SDK archives

From the runnable example directory, deliberately select or replace the SDK archives:

cd "$COMPANION"
mkdir -p vendor
cp "$WORLDSEQ_RELEASE/sdks/worldseq-sdk-0.1.0.tgz" vendor/
cp "$WORLDSEQ_RELEASE/sdks/worldseq_sdk-0.1.0-py3-none-any.whl" vendor/
# Only when selecting or replacing SDK archives:
rm -f bun.lock
bun install --ignore-scripts
bun node_modules/typescript/bin/tsc -p tsconfig.json

Removing this example’s old lock is intentional only when selecting or replacing the archives. Bun can otherwise retain cached contents for a different archive with the same package version, even after a successful install. The new lock records the selected archive. Keep it for subsequent installations of those unchanged files:

cd "$COMPANION"
bun install --frozen-lockfile --ignore-scripts
bun node_modules/typescript/bin/tsc -p tsconfig.json

The Python requirements file pins dependencies with hashes. Neither SDK needs public registry publication. A separately distributed companion may already contain matching SDK archives and compiled player files; preserve its lock when reinstalling those unchanged artifacts.

Export and run one language

Choose fresh export and job paths within your private operator workspace. Keep that workspace outside the source/distribution tree. Exports, credentials, seeds, trusted journals and certificates must remain private:

export PRIVATE_TASK_EXPORT=/absolute/private/operator-work/sdk-typescript-task
export PRIVATE_JOBS=/absolute/private/operator-work/sdk-jobs
cd "$WORLDSEQ_APP"
bun run worldseq harbor export draftlight.incident-week --out "$PRIVATE_TASK_EXPORT"

The task export must not already exist. This is a development demonstration. Use the operator guide and runtime CLI help for certified or private-suite exports; the companion does not create registrations, choose protected seeds, change fairness requirements, or issue credentials. Never copy a completed task’s session credentials into another run.

Decorate the fresh export for TypeScript, then let Harbor load the agent:

python3 "$COMPANION/prepare_export.py" "$PRIVATE_TASK_EXPORT" \
  --language typescript --runtime-source "$WORLDSEQ_APP"
sh "$PRIVATE_TASK_EXPORT/run-local.sh" \
  --agent worldseq_sdk_agents:TypeScriptSDKAgent \
  --n-concurrent 1 --jobs-dir "$PRIVATE_JOBS" --job-name sdk-typescript

For Python, create a different fresh export, then prepare and run it:

export PRIVATE_TASK_EXPORT=/absolute/private/operator-work/sdk-python-task
cd "$WORLDSEQ_APP"
bun run worldseq harbor export draftlight.incident-week --out "$PRIVATE_TASK_EXPORT"
python3 "$COMPANION/prepare_export.py" "$PRIVATE_TASK_EXPORT" \
  --language python --runtime-source "$WORLDSEQ_APP"
sh "$PRIVATE_TASK_EXPORT/run-local.sh" \
  --agent worldseq_sdk_agents:PythonSDKAgent \
  --n-concurrent 1 --jobs-dir "$PRIVATE_JOBS" --job-name sdk-python

prepare_export.py itself needs only Python’s standard library and the simulator’s Bun checksum helper. The exported run-local.sh places the export directory on PYTHONPATH, resolving the agent import. Do not run the bridge as a host-side player: Harbor must call environment.exec inside the configured player environment.

Clean image builds download dependencies. Player SDKs are installed during Docker build; no installation or Internet access is requested at player runtime. Preparation verifies the original export’s complete checksums, permits only environment/Dockerfile to change among original files, retains simulator/verifier hashes, and refreshes checksums through the selected runtime’s canonical helper. A second preparation is refused. Retain failed preparations and use a fresh export instead of retrying a partially modified directory.

Isolation and result evidence

The bridge preserves Harbor’s configured player user and environment. Setup checks UID 1000, read-only /public, absence of private seed/trusted episode paths and the Docker socket. Each player also checks that an outbound request fails. Credentials come only from the exact player-session file with strict field validation; there is no operator-token or environment-variable credential discovery.

Compose networking, task rules, simulator, collector, independent verifier and gameplay budgets remain unchanged. The trusted host harness needs Docker access; the player receives no Docker socket. Duplicate SDK decisions must return the same accepted receipt. The demonstration’s retained trusted journal checks one accepted decision and three waits.

A tested release companion can include validation-receipt.json with actual outcomes and hashes of its agent, player and helper files. That receipt is absent from the source checkout. Use it only for the exact artifacts it names; an edited checkout needs its own checks. Full operator evidence stays outside the distributable. Sanitized results record actual runtimes, SDK call counts, valid/eligible outcomes, budgets, zero model usage and trusted-file hash comparisons. Neither an eligible score nor a successful subprocess exit substitutes for those checks.

SDK archives, compiled JavaScript, dependency installations and actual task exports are local artifacts excluded from Git. Keep failed attempts and original receipts rather than replacing them with later successful runs.

Static and refusal checks

Run from the runnable example directory, with the matching simulator source’s development dependencies installed:

cd "$COMPANION"
bun checks/lint.mjs "$WORLDSEQ_APP"
bun node_modules/typescript/bin/tsc -p tsconfig.json
uv run --python 3.14 --with harbor==0.24.0 python -m unittest discover -s checks -p 'test_*.py' -v
uv run --python 3.14 --with harbor==0.24.0 --with mypy==2.4.0 \
  mypy --strict --follow-untyped-imports --follow-imports=silent \
  agents/worldseq_sdk_agents.py checks/test_bridge.py

--follow-untyped-imports makes mypy inspect the installed Harbor types despite Harbor’s missing py.typed marker; it does not replace the base class with Any. Use Ruff formatting/checks and strict mypy on prepare_export.py, checks/test_prepare_export.py, and player/play.py with the installed Python SDK. The refusal tests use disposable fixtures and mock only the checksum subprocess. Actual Docker tests use the real checksum helper, collector and verifier.

Controls reject malformed or altered exports, symlinks, missing checksum tooling, unknown languages, repeated preparation and changes to a trusted verifier file. Bridge controls retain failed player logs, propagate failure, and verify that calls never override the environment user or inject host credentials.

Pinned interface references

Harbor v0.24.0 defines the relevant interfaces in its agent base, environment base, agent context, and job CLI. These specify BaseAgent.name/version/setup/run, BaseEnvironment.exec, AgentContext, and the --agent module:Class syntax.