whileai-simulations
Skill0 starsChanged 51 days agoApache-2.0View on GitHub
Use the While simulations SDK to generate agent trajectories from a policy, tools, an agent harness, seed tasks, or production traces; focus generation on failures, grade with the developer's own authority, inspect quality, and export usable datasets. Use when a coding agent is asked to simulate an agent, expand coverage, turn traces into new scenarios, create eval or post-training data, or run the simulate-grade-select loop.
- Reads credentials
1 other project uses a version of this.
Adopted by
Most recently taken up by
- LMikeH/whileai-sdkword for word, first seen Oct 15, 2026
Other versions1 project uses a version of this.
Word for word · 1
- LMikeH/whileai-sdk★ 21100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository12 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- audit-your-judgeSkill
- characterSkill
- dpo-pairsSkill
- grpo-verifierSkill
- harness-searchSkill
- manage-experimentsSkill
- pick-a-methodSkill
- sft-from-tracesSkill
- strengthen-your-evalsSkill
- tool-call-efficiencySkill
- watchSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
20 rules. About 0 are common, 6 are distinctive, and 14 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
14
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 31
Use what the developer has:
- Distinctive: line 50
If traces exist, normalize and inspect them before spending generation budget:
- Distinctive: line 64
When traces are the starting point, follow this sequence:
- Distinctive: line 83
If schemas are unavailable, a mechanically inferred harness may be used as a reviewed draft, never silently as ground truth.
- Very specific: line 93
Run a 40-row trace-guided smoke test with the same agent definition and traces=normalized_traces.
- Very specific: line 103
Check wai.leakage_report(data.trajectories, normalized_traces) and keep source-trace copies out of generated data.
- Distinctive: line 129
Read every warning. Preflight and trace inspection are offline and need no model key.
- Very specific: line 134
Use mode="explore" for distinct situations, normally one row per situation.
- Very specific: line 136
Use mode="sft" when several human phrasings of each situation are useful.
- Very specific: line 137
Use mode="rl" with rollouts_per_request= when repeated attempts on the exact same ask are required.
- Very specific: line 142
Use mode="adaptive", until="saturation" for a broader run that mixes new situations, phrasings, and repeats until coverage plateaus.
- Very specific: line 177
Start with 40 rows. Close-read the smoke test before increasing to 200-400.
- Distinctive: line 256
every failed row and at least 20 passing rows.
- Very specific: line 289
When the ask is "build evals" or "improve the evals" for an agent the developer already runs, do not start from training data.
- Very specific: line 299
Put the ids the developer's world has (order numbers, account names) in the tool descriptions or in seeds=, one seed per policy branch.
- Very specific: line 302
Write the policy as the judge: read row["steps"], return reward, reason, markers (1.0 = the good outcome, None = not applicable).
- Very specific: line 316
Leave a CI gate (--gate 0.9, exit 1 under the floor, exit 2 when hollow) and a fast lane of offline judge tests on hand-labeled rows.
- Very specific: line 354
One run per arm is a draw, not a distribution: Use simulate(tasks=..., runs=3) so delta_report can compute the eval's own re-run noise.
- Very specific: line 358
Read the report's ceiling, warnings, within_noise and over_optimized fields, not just target_delta.
- Very specific: line 362
Before spending a GPU hour, check the eval can show a gain at all: pass_at(rows) gives pass@1, pass^k and headroom (pass@k minus pass@1, …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
While simulations
Operate While for the developer. Discover the context already present in their repository, choose the shortest valid input path, run a small smoke test, and return auditable data plus a run report. Do not require every possible input: policy, tools, traces, seeds, and a harness are complementary.
Terms in this skill: the developer is the person or team using While; the coding agent is the assistant reading this skill and operating the SDK; the target agent is the agent being simulated and improved; the simulated user is the person speaking to the target agent inside a trajectory.
Ground truth is the installed whileai.simulations package. Inspect its
public signatures when the installed version differs from these examples.
Inputs and routes
Use what the developer has:
tools=plussystem_prompt=: cold-start simulation across the declared agent and policy space.traces=plus the agent definition: mine observed failures and concentrate search on their tools, faults, world states, and behaviors. About 20 graded or fault-bearing traces gives useful targeting; below 10, treat the result mostly as cold-start exploration and say so. Traces reproduce situations (tools, faults, world states); a failure that lives in how the reply is worded has no world-visible trigger, so passgrader=as well and the loop mutates on graded failures too (search["mutation_aims"]).agent=: connect an existing callable, supported framework agent, command, or OpenAI-compatible model endpoint.spec=: load a repository folder containing the agent specification.seeds=: preserve specific developer-provided tasks as starting asks. Use repeats when the developer needs multiple attempts on the same task.execute=: let the developer's real harness answer tool calls when correctness depends on real state.
If traces exist, normalize and inspect them before spending generation budget:
traces = wai.load_traces(trace_source)
report = wai.trace_report(traces, tools=tools, policy=policy)
print(wai.format_trace_report(report))Traces guide generation; they do not replace the authoritative tool schemas or policy. Report foreign tools and missing context rather than silently inventing an agent definition.
Trace-first workflow
When traces are the starting point, follow this sequence:
- Locate the exact traces. They stay in the customer's own logs; the platform never receives them. Read the OTLP export or JSONL the deployment writes for the one agent and window asked about; do not guess from an unrelated file or silently combine different agents/days.
- Load local inputs with
wai.load_traces(...). JSONL paths and common message, rollout, tool-trace, and platform-export shapes are accepted. Usewai.rows_from_otel(...)first for raw OTLP/GenAI spans. Store the result asnormalized_tracesand use that same list for reporting, simulation, and leakage checks. - Print
wai.trace_report(...)before generation. Record rows dropped during normalization, graded/pass/fail/ungraded counts, observed tools, call-level faults, world states, distinct behaviors, foreign tools, and proposed grid emphasis. - Find the authoritative tool schemas and policy in the target agent's harness when possible. Traces show only tools and arguments that happened to run; they cannot reveal unobserved capabilities or recover a missing policy.
If schemas are unavailable, a mechanically inferred harness may be used as a reviewed draft, never silently as ground truth. Ask the developer to confirm required arguments and missing tools.
from whileai.simulations.ingest.traces import infer_harness draft = infer_harness(normalized_traces) tools, policy = draft["tools"], draft["policy"] # policy is intentionally empty- Run a 40-row trace-guided smoke test with the same agent definition and
traces=normalized_traces. - Inspect
data.search["trace_mining"]anddata.search["behavior_state"]. Confirm the input count is correct, expected failing tools/conditions were mined, focused dimensions changed, and the behavior-state allocation reportsapplied=True.data.metadata.targeted_rowsis meaningful only when an explicitsteering_weightwas used; zero is not evidence that ordinary trace-guided generation failed. - Compare the trace-guided run with a same-budget policy-only run. Report the share aimed at observed failures, not merely total row count.
- Check
wai.leakage_report(data.trajectories, normalized_traces)and keep source-trace copies out of generated data. - Grade the new rows with the developer-provided judge. Do not copy rewards from source traces onto newly generated situations.
- Save the returned
ScoredData; grading by judge creates scored copies and does not rewrite the original simulation file. - Feed newly graded failures into a later
simulate(traces=...)round only after preservingmodel_version, judge status, reason, and lineage.
A reward of 0 or an observed tool fault supplies direct repair signal. A
reward of 1 supplies contrast. Unlabeled traces still describe the observed
surface but do not establish correctness. Advisory model labels may steer
aiming, but report them separately from developer-owned grades.
Preflight
Find the exact system prompt the agent receives and obtain tool schemas from the implementation or harness rather than hand-transcribing them.
import whileai.simulations as wai
pre = wai.preflight(tools, policy)
print(pre)Read every warning. Preflight and trace inspection are offline and need no model key.
Choose the search
- Use
mode="explore"for distinct situations, normally one row per situation. This is the default and the best first run. - Use
mode="sft"when several human phrasings of each situation are useful. - Use
mode="rl"withrollouts_per_request=when repeated attempts on the exact same ask are required. It probes each ask with two rollouts and spends the rest of k on the asks whose rollouts disagree; passgrader=so the judge's reward decides, not the behavior signature. The allocation is indata.search["groups"]. - Use
mode="adaptive", until="saturation"for a broader run that mixes new situations, phrasings, and repeats until coverage plateaus.
Trace-guided repair and policy-guided discovery are both ordinary simulate
runs. The difference is whether traces= is supplied:
# BYOK; omit agent= to use While-hosted Qwen on the account key
# (`wai login`), or on VLLM_API_KEY for the shared pool when set.
agent = "openai:gpt-4.1-mini"
repair = wai.simulate(
agent=agent,
tools=tools,
system_prompt=policy,
traces=traces,
mode="explore",
budget=40,
time_budget=150,
grade=False,
output="simulations/trace_guided.jsonl",
)
discovery = wai.simulate(
agent=agent,
tools=tools,
system_prompt=policy,
mode="explore",
budget=40,
time_budget=150,
grade=False,
output="simulations/policy_guided.jsonl",
)Start with 40 rows. Close-read the smoke test before increasing to 200-400.
budget caps rows; time_budget caps wall time. situations controls distinct
worlds, requests_per_situation controls phrasings, and
rollouts_per_request controls independent repeats. Set them separately.
The default novelty embedder is deterministic hashing. Use an OpenAI embedding spec only when semantic novelty materially matters and the developer authorizes that endpoint and cost.
Model and world
For BYOK, set OPENAI_API_KEY and optionally OPENAI_BASE_URL, then use
agent="openai:<model>". The endpoint must implement OpenAI-compatible chat
completions with tool calls. The model writes the situations and plays the
target agent, so both consume its endpoint.
The same spec works for simulator= (the situation writer), user_model=
(the simulated person) and the judge's spec=. Backends: ollama:<model>,
vllm:<model>@<url>, openai:<model>, fireworks:<model> (an open model Fireworks
serves, on FIREWORKS_API_KEY), and anthropic:<model> for the Claude
Messages API on ANTHROPIC_API_KEY (WHILEAI_ANTHROPIC_API_KEY overrides it),
for example agent="anthropic:claude-haiku-4-5". Use anthropic: when the
developer's only credential is an Anthropic key, instead of falling back to
the template writer. typesafe:<model> (TypeSafe's Jev, on
TYPESAFE_API_KEY) is a judge-only spec for spec=: typed questions with a
probability per verdict and no text, so it refuses agent=, simulator=
and user_model=.
While normally builds a simulated world from the supplied tools, policy,
and traces. That is appropriate for record-shaped tools and behavioral
questions. If the evaluated agent edits code or correctness depends on a real
database/service, pass execute(tool_name, arguments) using the developer's
isolated harness. For code, use one disposable checkout per rollout and real
reads, writes, commands, exit codes, and hidden tests. If no safe harness
exists, report that prerequisite instead of treating invented files as truth.
Grade after simulation
The developer owns correctness. Prefer a callable judge that returns a reward
in [0, 1] and a reason. Judge errors remain unjudged; they are never silently
converted to failures.
def developer_judge(row: dict):
# Apply the target agent's policy, expected end state, tests, or evaluator.
return {"reward": 1 if developer_passes(row) else 0, "reason": developer_reason(row)}
scored = data.grade(judge=developer_judge, version="developer_judge@v3")
scored.save("simulations/scored.jsonl")
print(scored.report(tools=tools, system_prompt=policy))Pass version= so every scored row names the judge that labeled it (the
hosted wai.grade stamps its model and rubric hash itself). When the developer
has hand-labeled rows, write the label into gold_reward and report
scored.agreement(): agreement, kappa, and pass_when_gold_fail, the gold
failures the judge passed. Below 50 gold rows the estimate is coarse; say so.
grade=True grades against the developer's rubric with the judge; with no key
it stops. grade="conduct" is While's deterministic structural/conduct
screen, asked for by name; it is not the developer's semantic authority. Hosted or BYOK LLM grading is
optional. Keep unjudged rows out of selection and report judge failures.
data.grade(judge=...) deliberately leaves data.trajectories and the raw
simulation file unchanged; use the returned ScoredData from that point on.
Inspect before keeping rows
Reject a run when generator_fallback appears in data.degraded or
data.stopped_because == "writer_exhausted". Other degradation notes are
advisory; name them in the report and inspect their effect.
Always check:
- row count, unique prompts, stop reason, and degraded notes;
- tool names, argument/result linkage, empty or error rollouts;
- coverage by tool, policy rule, world state, condition, stance, and history;
- leakage against source traces and held-out evals;
- whether trace-guided generation actually emphasizes observed failure regions;
- every failed row and at least 20 passing rows;
- for real execution, that every call reached the intended isolated world.
Generated rows are candidates until the developer's judge and review accept them. Never overwrite existing evals, leak credentials, or merge generated cases silently.
Select and export
For eval expansion, keep reviewed cases in a new file with run provenance and integrate them only after developer approval.
For SFT after binary grading:
report = data.training_set("train.jsonl", target=1000, validate=True)This selects diverse passing demonstrations and applies the tool-call
round-trip export gate. For a judge-contract result returned as ScoredData,
use scored.select_for_sft() and wai.export_dataset(...) with the run's
policy and tools. For preference training, scored.select_for_preference()
pairs a passing and a failing rollout of the same prompt; read
report["warnings"] before exporting, it flags pairs where chosen is
usually the longer reply or where the two sides came from different models.
For RL, use repeated groups and select_for_rl; keep groups whole and
require meaningful within-group reward variation. Run with logprobs=True
when the rows will feed a trainer that corrects for off-policy sampling or
measures KL: each agent step then carries logprob and n_tokens, and
wai.logprob_report(rows) says what was captured.
Evals for an existing agent
When the ask is "build evals" or "improve the evals" for an agent the
developer already runs, do not start from training data. The path is
recipes/02-measure/eval-your-agent in the SDK repo and docs/evals.md:
- Wrap the agent as
agent(message) -> {"steps": [...], "final_text": str}. It runs its own real tools and is played single-turn. Record tool calls through athreading.local:concurrencydefaults to 32, so 32 rollouts call the function at once and one shared list mixes their calls together. Tools may be OpenAI-shaped (enveloped or bare) or Anthropic-shaped (input_schema, read asparameters). - Put the ids the developer's world has (order numbers, account names) in
the tool descriptions or in
seeds=, one seed per policy branch. Otherwise the writer invents ids and every rollout is "not found". - Write the policy as the judge: read
row["steps"], returnreward,reason,markers(1.0 = the good outcome,None= not applicable). wai.simulate(agent, tools=, system_prompt=, seeds=, simulator=False, mode="rl", repeats=4, repeat_policy="fixed", reproducible=True)first (offline), thensimulator="hosted"(the default, written out) for the hosted writer. Keeprepeatsat 4 or more orpass^kandpass@kcome backNone(min_k), and keepbudget >= situations * repeatsor the later situations never run. A hosted run takes minutes and logs its progress on thewhileai.simulationslogger at INFO.scored = wai.evaluate(data, judge)(pass the run itself so the declared tools are known);wai.pass_at(scored.rows)overall and per category. Readscored.warningsbefore any number: a run with no tool calls, an untouched declared tool or a marker on zero rows is hollow. Never report a pass@1 from a hollow run; fix the seeds or descriptions and rerun.- Leave a CI gate (
--gate 0.9, exit 1 under the floor, exit 2 when hollow) and a fast lane of offline judge tests on hand-labeled rows. - Judge trust:
wai.attach_labels(rows, labels, kind="human")thenwai.judge_trust(rows, judge). FAIL on eight labels means label more.
Names: install whileai. Two spellings per concept:
data.rows (exported, also data.rows()) beside data.trajectories (the
same rollouts before export), and scored.failures() beside
scored.failed_traces() / scored.traces.
Evaluate: did it move, and can the number be read?
Training is only half. The claim is "trained beats base on situations it never saw", and that claim has to survive someone checking it.
Pin the eval set first. simulate(tasks=...) fixes the situations so both arms
face the same ones; a re-run is not a baseline, it draws new situations. Hold
the eval out of training and check it with decontaminate(train, eval).
Then run both arms and compare:
report = wai.delta_report(before, after, target="pass_at_1", must_not_regress=["honest_on_fault"])
print(wai.format_delta_report(report))Three things make a delta unreadable, and none of them show up in the number. Check each before quoting a result:
- The arms must be distinguishable. Base and an adapter can share a served
model name, so both arms stamp the same
policy_versionand nothing says which weights produced which. Passadvanced={"model_version": "...-base"}and"...-sft". - The environment must not move with the arm. With no
user_model=, the simulated user runs on the agent's own model, so the trained arm talks to a different person than the base arm did and the delta measures the pair. Pinuser_model=to one fixed model on both arms. The run warns about this and addssame_modeltodata.degraded; do not ignore it. - One run per arm is a draw, not a distribution. Use
simulate(tasks=..., runs=3)sodelta_reportcan compute the eval's own re-run noise; without it the verdict readsmoved_unreplicated.
Read the report's ceiling, warnings, within_noise and over_optimized
fields, not just target_delta. A target_verdict of moved with ceiling
set means the eval had no room to show anything.
Before spending a GPU hour, check the eval can show a gain at all:
pass_at(rows) gives pass@1, pass^k and headroom (pass@k minus pass@1, what
a grouped update has to learn from), and per-criterion failure rates say
whether the eval contains the behaviour being trained. A criterion that never
fails cannot show an improvement. recipes/02-measure/is-your-eval-any-good/
runs all of this as one command.
Report the delta with its interval and the situation count, nulls included. A null on a sound setup is a result; a gain on an unsound one is not.
Deliverable
Return the generated JSONL and a concise report containing inputs used, model, seed/configuration, trace counts, search mode, row/coverage counts, grading method, rejected rows, leakage result, and review status. State what was simulated, what came from the developer's real harness, and what remains unverified.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

