Python SDK
The stateweave package: one client for everything the workspace does by API key. It uses
only the standard library and needs Python 3.10 or later.
pip install stateweave-sdkimport stateweave
client = stateweave.Client()
with client.start("t-bde537", agent="my-agent@0.1") as run:
result = run.finish(my_agent(run.prompt, run.apps))Client
stateweave.Client(url=None, api_key=None, timeout=300)| Parameter | Description |
|---|---|
url | Your workspace's address. Default: STATEWEAVE_URL, then what
sw login kept, then http://127.0.0.1:8700. |
api_key | An API key, sw_…. Default: STATEWEAVE_API_KEY, then
what sw login kept. Without one, Client() raises ValueError. |
timeout | Seconds to wait for each request. Starting a run and grading one each take a few seconds. |
Requests the workspace rate-limits per key (HTTP 429 rate_limited) are retried after the wait it asks
for, up to three times.
stateweave.start(...) and stateweave.tests(...) are shortcuts for the same methods on a
default Client().
me()
Returns {"studio", "name", "key": {"id", "name"}}: the workspace's address and name, and the key's.
Runs
tests(project=None)
The tests you can run, every scenario's or one's. Each is a dict with id, project,
project_title, title, prompt, kind, apps,
answer_format, persona and faults (how many it injects).
start(test, *, agent, project=None, timeout=None, meta=None)
Starts a run and returns a Run once its apps are up.
| Parameter | Description |
|---|---|
test | The test's id, t-…. |
agent | Required. The label runs are compared by, up to 80 characters. |
project | The scenario, when the test id is in several. |
timeout | Seconds before the run ends unfinished: 60 to 86,400. Default 1,800. |
meta | A JSON-able dict shown with the run, up to 4,000 characters as JSON. |
run(run_id)
A run you started, as it stands now.
next_run(worker, *, agent, meta=None, timeout=None, wait=25)
For a worker of your own: waits up to wait seconds (at most 30) for a run someone queued with Run
again, and returns it started, or None. worker is your worker's id (4 to 40 letters, digits,
- or _), the same on every call; calling keeps it listed as connected. sw worker
is built on this.
leave(worker)
Stops a worker: the workspace no longer lists it or queues runs for it.
Run
A run of a test, returned by start(), run() and next_run(). Use it as a
context manager: leaving the with block while the run is still going, because your agent raised or
finish() was never called, gives it up.
| Attribute | Description |
|---|---|
id | The run's id, r-…. |
test | The test's id. |
status | See Run statuses. |
prompt | The request to give your agent. |
kind | "answer" or "action". |
answer_format | For an answer test, an example of the JSON value to answer with. |
persona | Whom the agent acts for: {"name", "handle", "title"}. |
apps | Per app: base_url, endpoints,
credentials and mcp. See Apps and credentials. |
expires_at | When it times out, in Unix seconds. |
url | The run's page. |
data | The whole run as the API returned it. |
credential(app, kind="user")
The first credential of app whose label starts with kind: "user",
"bot", "app", "mcp" or "setup". None when there is
none.
mcp_servers()
The apps' MCP servers as {app: {"type": "http", "url", "headers"}}, the shape Claude Code and the
Claude Agent SDK take. Apps without one are left out.
finish(answer=None)
Hands in the answer (a JSON-able value; nothing for an action test), has the run graded, and returns its
Result. Raises RunEnded if the run had already ended.
cancel()
Gives the run up: its apps stop and it is not graded. Returns its Result.
result()
The run's Result as last seen, without a request.
Result
A dataclass describing how a run ended.
| Field | Type | Description |
|---|---|---|
id | str | The run's id. |
status | str | passed, failed,
timed_out, cancelled, interrupted or error. |
passed | bool | None | The verdict, once graded. |
reasons | list[str] | Why it passed or failed. |
calls | int | Calls your agent made to the apps. |
url | str | The run's page. |
Scenarios and data
projects()
Every scenario, newest first: id, title, description, apps,
status, error, company, steps and envs (per app its
counts, summary and state). No credentials.
project(project)
One scenario, the same shape.
create_project(description, apps, *, company=None, people=None, weeks=None, content=None)
Starts generating a scenario and returns it with status generating. content:
"auto" (Claude when the workspace has it), "llm" or "templates". See
Scenarios.
data(project)
{"kinds": {app: {kind: {"title", "fields", "example"}}}, "additions": [...]}: what each app takes, and
what was added so far.
add_data(project, app, kind, items)
Adds a list of items. Returns {"addition", "counts", "stale"}, stale being the number of
tests that now need a re-check. A bad item raises StateWeaveError listing every problem, and nothing is
added.
Tests
write_tests(project, requests, faults=None, *, noise=None, pinned=None, difficulty=None)
One test per request, its text kept word for word. Each request is a string, or a dict with text and
optionally criteria, kind and apps. Returns the job.
suggest_tests(project, count, focus="", faults=None, difficulty="normal", *, noise=None, pinned=None)
count tests (1 to 10) from Claude's ideas. difficulty: "normal" or
"hard". Returns the job.
Both take faults one way at most: faults (preset ids), noise (random injection, a dict;
{} for the defaults) or pinned (a list of faults at endpoints). See
Faults.
job(project, job)
A job writing tests: status (running, then done, or failed with
an error) and items, each
with status (pending, writing, checking, then
ready, failed or rejected), title, request,
test_id, detail and suggestion.
recheck(project, tests=None)
Re-checks the scenario's stale tests, or the ones named. Returns the ids being re-checked.
faults(project)
The fault presets: id, app, kind, title,
observed (seen on the real service) and evidence.
fault_targets(project)
Where faults can be pinned: {"apps": {app: {"title", "kinds", "endpoints"}}, "kinds", "noise": {"defaults",
"limits"}}. Each endpoint has an id, a label such as
PUT /api/v2/tickets/{ticket_id}, and the kinds that can happen there.
Errors
| Exception | When |
|---|---|
stateweave.StateWeaveError | The workspace refused a request. status is the
HTTP status, body the JSON it answered (error, and message or
problems). |
stateweave.RunEnded | A subclass: the run had already ended (timed out, cancelled,
finished). run is the run as it ended. |
ConnectionError | Nothing answered at the address. The message names it. |
ValueError | No API key anywhere, or faults given more than one way. |
try:
result = run.finish(answer)
except stateweave.RunEnded as e:
print("the run had ended:", e.run["status"])
except stateweave.StateWeaveError as e:
print(e.status, e.body.get("problems") or e.body.get("message"))Version
stateweave.__version__, or sw --version.