plurai-run-simulation is the runner behind /simulation-run. It plays each scenario of a scenario set against
your harness: a simulated user talks to your agent over the scenario’s seeded world, the mock environment serves
your agent’s tool calls, and the backend scores every eval. Run it yourself to score a suite from CI or a script.
Scenarios and evals are referenced by id. The runner needs only your simulate.py, not a local copy of the
scenarios.
Before you start
- The SDK is installed in your agent’s environment. See Install the SDK.
- You have built a suite, so your work folder holds
plurai_sim/.scenario_set_id,plurai_sim/.eval_set_id, andplurai_sim/.mock_service_urlfor the deployed mock environment. - You are signed in (
plurai login --status), orPLURAI_URLandPLURAI_TOKENare exported. The Run refuses to start without one.
Run the suite
--scenario-id to run every scenario in the set. Repeat it to run only some:
PLURAI_URL names. There is no URL or token flag.
Without --eval-set-id the Run plays every conversation but scores nothing, and the runner says so at the end.
What it does
- Checks that the backend is alive and accepts your token, and that the mock environment answers.
- For each scenario, opens a conversation on the backend and starts your harness in a child process.
- Seeds the scenario’s world and context, then alternates turns: your agent answers through
invoke_agent, and the backend’s simulated user replies. - When the conversation ends, sends the transcript, tool events and final world state to the backend, which scores every eval.
- Writes the per-scenario artifacts and a
run_summary.json, and prints a summary line.
Flags
Required
What to run
Mock environment
Budgets and retries
Regressions
Recording and identity
Checks
Outputs
Each scenario gets a folder<out>/<scenario_id>/:
The Run folder also holds
run_summary.json: the per-scenario status and verdict, scores, the trials block for
--trials, the stability annotations, and the turn cap with its source. A stability retry is kept in the
scenario’s stability_retry/ folder; a turn-cap re-run keeps the superseded attempt under previous_attempt/.
Exit codes
plurai-run-simulation, plurai and plurai-scan-contract share one exit code table. A code means the same thing
everywhere, and each command uses only the rows that apply to it. The names are constants in plurai.exit_codes, and
run_summary.json carries the same number in its exit_code field.
2 is never returned.
When a Run stops early
- A mock that cannot answer (
11). The token is rejected, the mock environment is not deployed, or the URL is not a mock. Nothing new starts, no score is reported, and stderr names what to change. A dropped connection is retried and does not stop the Run. - Credit (
20). When your organization is out of credit, nothing new starts. Scenarios that already finished keep their verdicts; the rest are recorded as incomplete, never as failed. stderr says what happened and, when a payment fixes it, points to your billing page. Before stopping, a scenario that is only waiting to start can wait for one of the Run’s own conversations to end. - Capacity or an outage (
20). If Plurai is in high demand or unavailable, the Run first waits and retries (a short backend restart passes unnoticed). If it stays down, the Run stops with one plain sentence, such as “Plurai is unavailable right now. Please try again in a few minutes.”
run_summary.json carries an aborted block with the reason, and a stopped Run does not update
.last_run.
To fail CI on eval results, fail on exit code 1, or read the verdicts from run_summary.json.
Run from your own Python code
plurai.orchestrator.Orchestrator drives a single scenario from Python. It is part of the supported surface, but the
command-line runner is the recommended entry point: it adds the preflight checks, trials, stability retries and
the summary. See the API reference.
Next steps
Run in CI
Run the suite on every change.
Write a harness
The
simulate.py contract the runner drives.