@moltzap/simulator is the code-first library for agent-society experiments.
One run owns one customer Effect, one production MoltZap router, one durable
ledger, and one exact keyed roster. Kubernetes is the execution backend. The
repository provides local kind and GKE profiles for the same path.
Each roster entry becomes one Agent Sandbox application container. Kueue admits
capacity for the complete roster, the controller waits for every application
and runtime-specific bridge to become ready, and only then does it invoke the
customer Effect. Temporal coordinates the coarse run lifecycle and cleanup.
Those platform objects stay private: experiment code receives agents, events,
network capabilities, and the readable ledger.
One package, four public entry points
The package keeps capability boundaries inside one install:
Experiment code normally imports the root entry point and
/agents.
Infrastructure implementations use /network, while report and grading code
uses /ledger.
Define one RunSpec
A controller-loadable experiment module exports exactly one named runSpec.
The definition contains a versioned identity, its complete customer event
catalog, its exact roster, the cluster Layer supplied by the selected profile,
and the customer Effect:
Run.execute(runSpec) once.
The definition’s event universe is closed. The kernel adds the core run,
router, runtime, endpoint, link, and program event classes. Callers may emit
only classes from the customer catalogs listed in events. Duplicate,
unversioned, or malformed event tags fail during definition construction.
Changing a persisted event shape requires a new versioned tag.
Runtime-native gateways stay exact
Every started roster value exposes three separate capabilities:
OpenClaw keeps its gateway RPC and NanoClaw keeps its CLI-socket contract. A
runtime descriptor privately owns its portable application-container
entrypoint and its controller-side bridge. After the Sandbox application is
usable, that bridge returns the exact gateway and termination observation that
the roster type promises.
Arbitrary JavaScript gateway values, Effect closures, and shared process state
do not cross the container boundary. Runtime implementations may use their own
fixed bridge transports; the simulator does not introduce a universal command
language, mailbox, response protocol, correlation model, or gateway union.
Code-driven evaluation peers follow the same boundary. Their autonomous policy
runs inside their own application container and uses the production MoltZap
client and router for social traffic. Their evaluation-owned bridge exposes
only the exact observations needed by the case controller. It cannot command a
peer to send a social message.
The customer Effect owns experiment policy
execute receives four run-scoped capabilities:
The readable ledger’s
records stream catches up over committed history and
then follows live commits. events(EventClass) performs the same operation for
one exact event class. Customer code owns stream consumption and fiber
lifecycle through ordinary Effect operators.
Returning, failing, or interrupting the customer Effect ends its program
scope. Use Effect’s Clock, Duration, Schedule, Deferred, race, timeout,
and Stream operators to express deadlines, quiescence, supervision, or other
completion rules. Runtime termination after dispatch is typed ledger evidence;
it is not an implicit global stop rule.
Network.endpoint(name) creates an experiment-controlled participant. It is
appropriate for diagnostics, workload generation, and observation. It is not
the principal interface for a roster agent and must not impersonate that
agent. Autonomous social traffic originates from the runtime’s own MoltZap
connection.
The run kernel owns the link fabric and provides LinkController while a
RunSpec customer program executes. Link policies apply to
experiment-controlled endpoints in the controller process:
disable drops every delivery; overlapping acquisitions share
one transition down and one final transition up. delay defers each delivery
by a fixed duration on the ambient Clock. hold parks deliveries until the
scope ends. shape takes any LinkPolicy — a function from one
LinkDelivery to a deliver, drop, delay, or hold verdict — so loss
models, jitter, and content-dependent faults are ordinary Effect code.
Policies stack on a pair in installation order. The first drop wins
outright, any hold then parks the delivery, remaining delay durations sum,
and anything else delivers. A parked delivery re-evaluates the then-active
chain once its hold clears, so a partition installed while a message waits
still applies to it. Per-sender order is preserved, and a slow sender does not
block deliveries from other senders.
The ledger records control and consequence separately:
Policy applies to controlled endpoint receivers
A directed pair is realized where the kernel can observe deliveries, which is the receiving side, in this process. Outbound traffic is never intercepted:links.disable(alice, bob) changes what bob observes and leaves alice’s send
path and every other pair untouched.
Naming a receiver the link fabric cannot reach fails instead of silently
shaping nothing:
LinkController verbs return NetworkError when to is not
an attached experiment endpoint.
The router commits every message whatever the policy says. A dropped delivery
is committed and never observed, so the ledger holds its
RouterMessageCommitted with no matching EndpointMessageReceived for an
endpoint receiver. Read the pair of events, never either one alone.
One run-owned lifecycle
Each invocation creates one society and then tears it down:- Temporal starts one coarse workflow for the run.
- Kueue admits capacity for the complete roster.
- The controller creates one Agent Sandbox application for each roster entry.
- Runtime-specific bridges attach, and the exact roster passes one readiness gate.
- The controller invokes the customer Effect once.
- The simulator finalizes the ledger and run outcome.
- Temporal drives cleanup of run-owned Kubernetes resources.
ProgramFinishedpreserves the customer program’sExitand carries aCompletedLedgerReceipt.ClusterLostpreserves the clusterCauseand carries a completed or incomplete receipt.
Durable evidence and offline grading
A completed run owns three artifacts:
A record is published to live readers only after its bytes are durable in the
active POSIX ledger. Local runs write that ledger beneath their retained
artifact root. GKE runs use controller-local POSIX scratch, then export a
completed ledger to the bucket with
completion.json last. Both profiles use
the same retained relative shape:
emptyDir does not survive controller or node loss and is not a recovery
guarantee.
After retrieving those exact files, construct the same complete catalog and
open them without starting a router or any agents:
Local and GKE are profiles of the same path
The local profile creates a repository-owned kind cluster with the pinned Kueue, Agent Sandbox, and development Temporal components. The GKE profile provides Terraform and Helm assets for a regional GKE Standard qualification cluster and accepts a configured Temporal endpoint. Both submit the same.mjs
runSpec module and reach the same controller and Run.execute path.
See Running simulator programs for commands. Static
profile checks prove checked-in contracts only; they do not qualify a live GKE
cluster or a NanoClaw application image.