blankstate-sdk
Python client for the Blankstate API (import package blankstate_sdk; PyPI distribution blankstate-sdk).
Measure interactions against behavioral protocols — get a score, per-metamarker resonance, signal analysis, and fidelity assessment. The engine runs server-side; this package handles auth, request formatting, and typed responses.
Install
pip install blankstate-sdk
Requires Python >= 3.10. Uses httpx for async HTTP and pydantic for typed responses.
Quick Start
import asyncio
from blankstate_sdk import Blankstate
bks = Blankstate(token="your_api_token")
async def main():
result = await bks.sense("proto-xxx:1.0", "The agent resolved the issue promptly.")
print(result.score) # 0.82
print(result.resonance) # {"Solution-Oriented": 0.96, "Empathy": 0.41}
print(result.fidelity) # index=0.74 sufficient=True
print(result.ics.consumed) # 2
asyncio.run(main())
Or set your token via environment variable:
macOS / Linux:
export BLANKSTATE_API_TOKEN=bks_your_token
Windows:
$env:BLANKSTATE_API_TOKEN = "bks_your_token"
import os
from blankstate_sdk import Blankstate
bks = Blankstate(token=os.environ["BLANKSTATE_API_TOKEN"])
API
Blankstate(token, *, api_url=..., user_agent=...)
| Parameter | Type | Default | Description |
|---|---|---|---|
token |
str | BlankstateOptions |
— | API token (required), or pass BlankstateOptions as the only positional argument |
api_url |
str |
https://api.blankstate.ai |
API base URL (BLANKSTATE_API_URL if omitted) |
user_agent |
str |
blankstate-sdk |
User-Agent header sent with every request (including healthy()) |
Equivalent to the JS options object:
from blankstate_sdk import Blankstate, BlankstateOptions
bks = Blankstate(BlankstateOptions(token="...", api_url="https://api.blankstate.ai"))
Response models live in blankstate_sdk.models (import types from there for annotations).
Sense
Measure content against a protocol. The measurement engine version is set by the protocol definition — not by the caller.
result = await bks.sense(
"proto-xxx:1.0",
content,
language="en", # default: "en"
profile="detailed", # "raw" | "detailed" | "discovery"
depth="full", # "measure" | "full"
)
result.score # overall alignment (0.0–1.0)
result.resonance # {"Empathy": 0.91, "Solution-Oriented": 0.76}
result.signal # spread, coherence, dominant_mode (v1.5 protocols)
result.actant_flow # entity influence direction (v1.5 protocols)
result.temporal # temporal trend analysis (v1.5 protocols)
result.fidelity # index, sufficient
result.ics # consumed, cost_usd, sgm_version, pool
Measure against multiple protocols in parallel:
results = await bks.sense_multiple(
["proto-aaa:1.0", "proto-bbb:2.0"],
content,
)
# returns dict[protocol_id, SenseResponse]
# failed protocols are silently dropped
Fidelity Check — 0 ICS
Pre-check whether content has enough signal for measurement before spending ICS:
check = await bks.fidelity_check("proto-xxx:1.0", content)
check.fidelity.sufficient # True | False
check.fidelity.index # 0.74
check.estimated_ics # ICSRange(min=1, max=3, typical=2)
Status and Usage
status = await bks.status()
# status.authenticated
# status.sgm_versions — {"1.0": "stable", "1.5": "extended"}
# status.ics.remaining
# status.ics.member — member-level cap if set
usage = await bks.usage()
# usage.ics_used, usage.ics_remaining, usage.ics_total
estimate = await bks.usage_estimate(content_length=500, modality="text")
# estimate.estimated_ics, estimate.will_exceed_quota
Protocols
# List protocols in your account
protocols = await bks.protocols()
# [ProtocolSummary(id=..., name=..., versions=[...], sgm_version=...)]
# Get a protocol's full definition
definition = await bks.protocol("proto-xxx:1.0")
# definition.id, definition.name, definition.version, definition.sgm_version
# definition.metamarkers — [ProtocolMetamarker(label=..., description=...)]
# definition.taxonomy, definition.supported_modalities
Programmatic Dive
opened = await bks.dive.open({"stage_id": "stg_…", "agent": {"id": "my-agent", "version": "1"}})
await bks.dive.act(opened.dive_id, {"action": "Inspect the records", "turn": opened.observation.turn or 0})
await bks.dive.status(opened.dive_id)
await bks.dive.close(opened.dive_id, {"summary": "done"})
Stages
A Stage is the situation you author and version; a World is one run of it. Writes are applied whole or
refused whole: a BlankstateAPIError carries issues (422, 423) or the current rev (409).
made = await bks.stages.create({
"world": "proxy",
"premise": "Claims appeals in the UK: members contest decisions, assessors review.",
"ops": {"actants": [{"label": "Member", "kind": "group"}, {"label": "Assessor", "kind": "person"}]},
})
rev = (await bks.stages.get(made.id)).rev
await bks.stages.edit(made.id, {
"if_rev": rev,
"ops": {"links": [{"from": "Member", "to": "Assessor", "surface": "chat", "relation": "files the appeal"}]},
})
checked = await bks.stages.check(made.id)
stages = await bks.stages.list()
estimated = await bks.stages.estimate(made.id, {"span": 20})
started = await bks.stages.start_world(made.id)
await bks.stages.set_world(made.id, started.world_id, "paused")
world = await bks.stages.world(made.id, started.world_id, {"trajectories": True})
| Method | Arguments | Does |
|---|---|---|
stages.list() |
— | Your Stages: id, title, world, rev, Worlds run |
stages.create(params) |
world ("proxy"), premise, scale?, ops? |
A Stage from a premise, with typed operations. Applied whole or refused whole |
stages.get(stage_id) |
The outline and rev |
|
stages.edit(stage_id, params) |
if_rev, ops |
Typed operations against the rev you read. A stale rev is a BlankstateAPIError carrying the current rev (409) |
stages.check(stage_id) |
What is thin, each with a question, and the gaps | |
stages.estimate(stage_id, params) |
span, seed? |
What span days (or turns) ask on a seed: interactions, agents, minutes / minutes_max, ICS range, and what each objective read on events would count (expect). Spends nothing |
stages.start_world(stage_id, run=None) |
budget_ics?, minutes?, until_day?, pauses?, target?, seed? |
Start a World. Answers at once; follow it with world |
stages.set_world(stage_id, world_id, state, run=None) |
state: "running" | "paused" | "stopped" |
Pause, stop, or carry on. Run options go only with "running" |
stages.worlds(stage_id) |
The Stage's Worlds, newest first | |
stages.world(stage_id, world_id, opts=None) |
trajectories? |
Status and outcome: day, objectives, spread, levers, proposals, ICS, next_steps |
stages.review(stage_id, world_id, params) |
keep?, discard? |
Keep or discard proposals by id |
stages.rename_world(stage_id, world_id, name) |
Rename a World | |
stages.delete_world(stage_id, world_id) |
Delete a World. One still running stops first | |
stages.versions(stage_id, opts=None) |
from?, to? |
Kept versions, and what changed between two |
stages.restore(stage_id, params) |
if_rev, version |
Make a kept version the Stage again |
stages.create_variant(params) |
stage, world, label, varies, question? |
A Variant on the version that World ran on. varies is one or more of system, population, environment, clock |
The token needs stages:read and stages:write to create or edit, and runs:dry to estimate, start, pause, and carry on Worlds.
Health
ok = await bks.healthy() # True | False — 0 ICS, no auth required
Error Handling
from blankstate_sdk import BlankstateAPIError
try:
result = await bks.sense("proto-xxx:1.0", content)
except BlankstateAPIError as err:
print(err.status_code) # HTTP status code
print(err.error_message) # human-readable message
print(err.code) # machine-readable error code
if err.is_auth_error(): # 401/403 — check your token
...
if err.is_quota_error(): # 429 — ICS quota exceeded
print(err.ics_info) # {"quota": 50, "used": 50, "remaining": 0}
if err.is_server_error(): # 5xx — retryable
...
Development
This package has its own pyproject.toml. From the repo root:
git clone https://github.com/blankstate-ai/blankstate-py.git
cd blankstate-py
python3 -m pip install -e "./packages/sdk[dev]"
pytest packages/sdk/tests
Or from packages/sdk/:
cd packages/sdk
pip install -e ".[dev]"
pytest
Concepts
| Term | Description |
|---|---|
| Protocol | A behavioral sensor — defines metamarkers that characterize an interaction pattern |
| Metamarker | A named behavioral signal (e.g., "Empathy", "Escalation Risk") |
| Resonance | Activation strength of each metamarker (0.0–1.0) |
| Score | Aggregate alignment between content and the protocol |
| Fidelity | Signal quality — whether content has enough substance for reliable measurement |
| ICS | Interaction Computed Signal — billing unit per measurement |
| SGM | Blankstate measurement engine — v1.0 (stable), v1.5 (extended signal analysis) |
Requirements
- Python >= 3.10
- API token from atlas.blankstate.ai
Links
- Atlas — Dashboard, API tokens, protocol management
- API Reference — Full REST API documentation
- Issues — Bug reports and feature requests
License
MIT — blankstate.ai
Metadata
Release files for blankstate-sdk 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| blankstate_sdk-0.5.0.tar.gz | 22.1 kB | Without provenance | Details for blankstate_sdk-0.5.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| blankstate_sdk-0.5.0-py3-none-any.whl | Python 3 | none | any | Details for blankstate_sdk-0.5.0-py3-none-any.whl |
Total release size: 41.2 kB
Release files / blankstate_sdk-0.5.0.tar.gz
| Download URL | blankstate_sdk-0.5.0.tar.gz |
|---|---|
| Size | 22.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6fc9a168ea95b92f36b52b8ecba1374f1df7db68ce30e2b7d0b7cf59083ebd96
|
|
BLAKE2b-256 checksum How to use checksums |
91c0930d95a45d9549e7f6498dca95dcb9c27402af099e2e17628349a60a4aed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / blankstate_sdk-0.5.0-py3-none-any.whl
| Download URL | blankstate_sdk-0.5.0-py3-none-any.whl |
|---|---|
| Size | 19.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
09c2348b3bbd1ba18ec0b5f92b9e6b73298df8a967eb400a70396cfbb427da93
|
|
BLAKE2b-256 checksum How to use checksums |
9c7fa0b3496d3042eb4c8238e97edfb7cf8bd56ca93c6673044120505b10d8ec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Security for blankstate-sdk 0.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.