One-line, agent-led install for Storm commercial metering (qualified engineering results — generative CAD & simulation).
Reason this release was yanked:
client wire-contract mismatch; use ≥0.3.0
Project description
storm-billing
Dependency-free Python SDK and one-line, agent-led installer for Storm's commercial metering (qualified engineering results — generative CAD & simulation).
pip install storm-billing
This installs a storm CLI, an onboarding kit designed to be driven by your coding
agent, and an optional typed SDK:
storm init # write the onboarding kit into your project
storm agent-guide # runbook + interview the agent asks you
storm adapter inspect SAMPLE # offline: propose a mapping for your own events
storm doctor # read-only config + reachability check
storm provision --plan # transparent plan; --apply after you approve
storm verify # authorization smoke test
This wheel is onboarding and provisioning tooling. It does not need to become a
runtime dependency of your product. In the customer-hosted topology a pilot
deploys, raw telemetry stays in your own Kafka/MSK log and a digest-pinned Storm
projector reads it; your product runtime makes one synchronous HTTPS call at
operation submission, which you can make with whatever HTTP client you already
have. If you want that call written out for you rather than typed, copy
examples/control-client/storm_control_client.py
— one file, standard library only.
Reach for the SDK (from storm_billing import StormClient) when you want the
accelerators: Shape A event builders, canonical evidence attestation, batch
receipts, deterministic fixtures.
Enterprise-safe by design: a plain PyPI install (no curl | sh), a pure-Python wheel with
no install-time code, and no network or mutation until you explicitly run a storm command.
See https://stormbilling.dev/docs/install for the full flow.
SDK reference
Integration boundary
The SDK emits raw workflow observations; it cannot declare a result qualified, billable, accepted, priced, or certified. Storm's versioned deterministic policy owns qualification.
The customer-facing meter is qualified_engineering_result. One contract
catalog covers DESIGN_GENERATION and SIMULATION_ANALYSIS. A top-level
customer operation earns at most once after terminal technical success,
verified evidence, customer-visible availability inside the product, and a
complexity class derived from locked inputs.
Resource telemetry such as tokens, model/tool calls, solver/GPU/CPU seconds, storage, retries, and cache hits is retained for cost and margin analysis. It does not directly set the customer price or create a statement line.
Compatibility high-throughput client — not the pilot path
StormEdgeClient belongs to the earlier Storm-managed data plane and to the
throughput benchmarks. A customer-hosted pilot does not use it, and onboarding
never configures it. It is retained and supported for deployments already on that
topology; described here so the behaviour is documented, not to recommend it.
It preserves the same submission identity and encoded body across transient retries and does not make one remote request per event. The first production-shaped pilot instead keeps raw telemetry in the customer's Kafka/MSK log and runs Storm's digest-pinned projector in the customer account.
- Embedded mode returns
LOCAL_WALafter the local encrypted WAL durability boundary. - Agentless mode returns
REMOTE_LOGonly after the replicated log acknowledges the batch; a partition fails fast. - Durable acceptance does not mean the result qualified.
Batching support by itself is not a throughput claim. A retained
AWS_PRODUCTION_LIKE run measured the replicated-ingress tier at 1,071,440
events/second over about 600 seconds for the 1-KiB profile with zero measured log
loss; it did not prove real-time commercial-path completion at that rate.
import os
from storm_metering import (
StormClient,
StormEdgeClient,
engineering_operation_started_event,
engineering_resource_recorded_event,
engineering_result_available_event,
engineering_result_completed_event,
)
customer_id = "nova-propulsion"
customer_operation_id = "operation-wing-design-001"
work_item_id = "wing-design-001"
input_fingerprint = "a" * 64
result_content_hash = "b" * 64
complexity = {
"domain": "aerospace",
"fidelity": "HIGH_FIDELITY",
"constraint_count": "180",
"geometry_feature_count": "4200",
"assembly_component_count": "240",
"optimization_candidate_count": "1200",
"required_evidence_level": "VERIFIED",
}
common = {
"customer_id": customer_id,
"customer_operation_id": customer_operation_id,
"work_item_id": work_item_id,
}
events = [
engineering_operation_started_event(
**common,
event_id="operation-wing-design-001-started",
time="2026-07-19T18:00:00.000Z",
commercial_intent="CUSTOMER_REQUESTED",
result_type="DESIGN_GENERATION",
input_fingerprint=input_fingerprint,
declared_complexity_inputs=complexity,
qualification_deadline_at="2026-07-20T18:00:00.000Z",
),
engineering_resource_recorded_event(
**common,
event_id="operation-wing-design-001-gpu",
time="2026-07-19T18:05:00.000Z",
attempt_id="attempt-001",
meter="gpu_seconds",
quantity="720.000000",
disposition="ORIGINAL",
),
engineering_result_completed_event(
**common,
event_id="operation-wing-design-001-completed",
time="2026-07-19T18:12:00.000Z",
attempt_id="attempt-001",
result_id="result-wing-design-001",
result_content_hash=result_content_hash,
input_fingerprint=input_fingerprint,
result_type="DESIGN_GENERATION",
terminal_state="SUCCEEDED",
design_status="COMPLETE",
requirements_satisfied=True,
final_complexity_inputs=complexity,
operation_started_at="2026-07-19T18:00:00.000Z",
operation_completed_at="2026-07-19T18:12:00.000Z",
evidence_refs=["verified-evidence-record-001"],
tool_version="design-tool-2026.1",
),
engineering_result_available_event(
**common,
event_id="operation-wing-design-001-available",
time="2026-07-19T18:13:00.000Z",
result_id="result-wing-design-001",
result_content_hash=result_content_hash,
availability="CUSTOMER_VISIBLE",
result_reference="product://workbench/results/result-wing-design-001",
),
]
# Admission is a control-plane decision, not telemetry ingestion. Storm derives
# the price and reserves exact currency; the producer never supplies an amount.
control = StormClient(
base_url=os.environ["STORM_CONTROL_PLANE_URL"],
ingest_api_key=os.environ["STORM_TELEMETRY_API_KEY"],
control_plane_api_key=os.environ["STORM_COMMERCIAL_API_KEY"],
)
admission = control.authorize_engineering_operation(events[0])
if not admission["allowed"]:
raise RuntimeError(
f"Engineering operation denied: {admission['reason']}"
)
edge = StormEdgeClient(
edge_url=os.environ["STORM_EDGE_URL"],
edge_token=os.environ["STORM_EDGE_TOKEN"],
# Prefer gzip for a regional/agentless hop; local sidecars may use "none".
compression="gzip",
)
receipts = edge.submit_events(
events,
submission_id="operation-wing-design-001-workflow",
)
For SIMULATION_ANALYSIS, provide convergence_status, residual, and
max_constraint_violation instead of design fields. A nonconvergent simulation
cannot earn the commercial result.
Use StormClient separately for scoped control-plane operations: central
operation authorization, reservation lookup, evidence, qualification
explanations, statements, CSV download, exports, and settlement destinations.
Admission denial (402) is returned as a typed decision; malformed,
unauthorized, and unexpected responses still raise StormApiError. Bounded
edge-lease allocation is an explicit experimental compatibility seam, not a
first-pilot requirement. Legacy finalized-simulation and internal-cost helpers
remain for the Postgres compatibility path; new high-throughput integrations
should use the four workflow builders above.
Engineering artifacts stay in customer-owned systems. Send only immutable hashes, US-resident references, and evidence metadata.
The first deployment profile targets AWS us-west-2, but the SDK makes no
assumption about your cloud. It depends only on Storm's HTTP contracts and does
not embed an AWS dependency.
See docs/api-contract.md, docs/architecture/high-throughput-data-plane.md,
https://stormbilling.dev/docs/data-plane, and
openapi/storm-agent-api.openapi.json.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file storm_billing-0.2.0.tar.gz.
File metadata
- Download URL: storm_billing-0.2.0.tar.gz
- Upload date:
- Size: 57.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
843f4fb23dc636b82e11f456543fb59f8837826374ff67389f3923c6492951c7
|
|
| MD5 |
b4c1c74f4145957ba2a6af94098c6c3b
|
|
| BLAKE2b-256 |
59d15b005d1a16cc5425f0630a789c9b773ae38f75ed1ccdf5346632232c08db
|
File details
Details for the file storm_billing-0.2.0-py3-none-any.whl.
File metadata
- Download URL: storm_billing-0.2.0-py3-none-any.whl
- Upload date:
- Size: 65.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d40946e62e888797635da3ed8c93eae8dd9f5df5ed5aa00fe673eb99e4575152
|
|
| MD5 |
40070b054c9d08fbe929e4056f8190bb
|
|
| BLAKE2b-256 |
5390ca0532ad6da534f286b1a090bf49b2215d97ddc5ee98ee21f631677baa23
|