Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

HaltState SDK

PyPI

Action control and Proof Packs for autonomous AI agents. Perform pre-action checks, approvals, and post-action reporting with minimal code.

Semiotic Probe (source candidate, not activated)

probe = client.connect_semiotic_probe("openai", "gpt-4.1", lambda raw, limit: isolated_model(raw, max_tokens=limit))
# Or use probe.poll_once() and probe.close() in an application-owned lifecycle.

The hook must be fresh and isolated: no history, memory, retrieval, tools, or side effects.

Canonical public base URL: https://haltstate.ai

Canonical governance namespace: /api/haltstate/sentinel/*

Current SDKs default to https://haltstate.ai. Guard endpoints use the branded /api/haltstate/sentinel/* namespace when available. The released check(), report(), and approval-polling paths still use supported legacy /api/sentinel/* compatibility aliases until matching branded backend routes are registered.

Replay safety status

Replay-ledger hardening is implemented and locally verified in this source tree. Production activation remains pending the caller-first quiesce/drain window, migration 106, matching API/SDK deployment with no mixed workers, and the delayed/replay route smokes; this is not a production-live claim.

On the hardened path, each tenant and idempotency key binds to one exact operation: agent, action, resource, normalized parameters, and risk class. The stored decision carries the evaluated policy version; a retry with changed operation data is rejected. Approvals expire, and an eligible operation receives at most one permit. Exact outcome-report retries receive the original receipt.

The durable lifecycle is recorded in an append-only, hash-chained event log. That log is not externally anchored or immune to a database superuser. Destination idempotency remains the customer's responsibility: HaltState cannot guarantee exactly-once execution inside an external payment, email, or infrastructure system. Hosted LLM inference is likewise not claimed to be bit-for-bit deterministic.

Post-cutover idempotency epoch

During the controlled replay-ledger cutover, configure the UUID epoch issued for that activation:

client = HaltStateClient(
    tenant_id="acme",
    api_key="hs_xxx",
    idempotency_epoch="11111111-2222-4333-8444-555555555555",
)

After configuration, guard() calls that omit idempotency_key generate a qualified key in the form hsr1:<epoch>:<uuid>. The SDK never prefixes, rewrites, or upgrades an explicit caller-supplied key. Consequently, explicit keys sent after cutover must already be fully qualified for the active epoch. Keep idempotency_epoch unset only for preactivation compatibility, where omitted keys retain the legacy plain-UUID behavior. Keep this HaltState guard key separate from the destination's stable business idempotency key; the destination key must not rotate with the guard epoch.

Configure the epoch only after guarded callers and schedulers are quiesced, guard ingress is closed, legacy API workers are stopped, and old work is drained or reconciled. Reopen with no mixed workers. Once epoch-qualified work is admitted, do not roll back to a pre-replay binary under open ingress; remain fail closed and roll forward.

Installation

PyPI currently serves 0.7.0. The replay-safe contract in this tree is the unpublished 0.8.0.dev0 candidate and must be installed from the reviewed source checkout until it is released.

# Published baseline:
pip install haltstate-sdk

# Replay-safe source candidate, from the repository root:
pip install ./packages/haltstate-sdk

Quickstart (sync)

from haltstate import HaltStateClient

client = HaltStateClient(
    tenant_id="your_tenant_id",
    api_key="hs_xyz",
    base_url="https://haltstate.ai",
    fail_open=False,
)

decision = client.check(
    action="payment.process",
    params={"amount": 5000, "currency": "USD"},
    agent_id="payment-bot-01",
)

if decision.allowed:
    process_payment(...)
    client.report(decision, status="success", result={"transaction_id": "tx_123"}, action="payment.process", agent_id="payment-bot-01")
elif decision.requires_approval:
    print(f"Approval required: {decision.reason}")
else:
    print(f"Action denied: {decision.reason}")

Guard Pattern

For actions requiring human approval, use the idempotent guard pattern:

from haltstate import HaltStateClient, ApprovalPending, ActionDenied

def process_high_value_payment(invoice_id: str, amount: float):
    operator_epoch = "11111111-2222-4333-8444-555555555555"
    destination_key = f"payment-{invoice_id}"
    guard_key = f"hsr1:{operator_epoch}:{destination_key}"
    report_id = "40000000-0000-4000-8000-000000000501"
    client = HaltStateClient(
        tenant_id="acme",
        api_key="hs_xxx",
        base_url="https://haltstate.ai",
    )

    try:
        with client.guard(
            action="payment.process",
            agent_id="payment-bot",
            params={"invoice_id": invoice_id, "amount": amount},
            idempotency_key=guard_key,
            resource=f"invoice/{invoice_id}",
            risk_class="high",
            report_id=report_id,
        ) as permit:
            permit.validate_for_execution()
            result = execute_payment_once(
                invoice_id=invoice_id,
                amount=amount,
                idempotency_key=destination_key,
            )
            print(f"Approved by {permit.approver} at {permit.approved_at}")
            return result

    except ApprovalPending:
        print("Awaiting human approval...")
        return {"status": "pending"}

    except ActionDenied as e:
        print(f"Denied: {e.reason}")
        raise

Key features:

  • Exact operation binding: The same key and same proposal replay the stored decision; changed agent, action, resource, risk, or parameters conflict.
  • Expiring approval authority: Approvals expire, and the SDK refuses an expired executable response before entering the action.
  • One-permit rule: A retry after permit issuance receives an ActionAlreadyStarted error, not replacement authority. A lost permit or missing outcome report requires destination reconciliation.
  • Durable outcome reporting: Exact report retries reuse their receipt; exhausted reporting retries raise OutcomeReportError.
  • Replay evidence: Policy-versioned decision, approval, permit, and outcome events form an append-only hash chain.

Retries while an approval is still pending can safely poll the same exact operation. A restart after permit issuance must not blindly execute the action again; reconcile against an idempotent destination first.

Persist the permit, report_id, outcome, and exact payload before an outcome retry. If the context manager raises OutcomeReportError after the side effect returns, resume only the receipt call:

receipt = client.report_guard_outcome(
    permit,
    report_id=report_id,
    outcome="success",
    result={"destination_key": destination_key},
)

Do not rerun the payment to obtain that receipt. Error outcomes use the same public method with outcome="error" and the same caller-stable UUID.

Decorators

from haltstate import HaltStateClient, haltstate_guard

client = HaltStateClient(tenant_id="acme", api_key="hs_xxx", base_url="https://haltstate.ai")

@haltstate_guard(client, action="email.send", agent_id="email-bot")
def send_email(to, subject, body):
    return mailer.send(to, subject, body)

Async

from haltstate import AsyncHaltStateClient

async def main():
    async with AsyncHaltStateClient(tenant_id="acme", api_key="hs_xxx", base_url="https://haltstate.ai") as client:
        res = await client.check("database.drop", params={"table": "users"})
        if res.allowed:
            await client.report(res, status="success", action="database.drop", agent_id="ops-bot")

Exceptions

from haltstate import (
    HaltStateError,           # Base error
    HaltStateAuthError,       # Invalid API key
    HaltStateConnectionError, # Network/timeout
    ApprovalPending,          # Awaiting approval (guard pattern)
    ActionDenied,             # Human rejected (guard pattern)
    ActionExpired,            # Approval expired (guard pattern)
    ActionAlreadyStarted,     # Permit already issued; never rerun the action
    OutcomeReportError,       # Durable outcome receipt was not confirmed
)

Docs

Full documentation at haltstate.ai/docs:

  • Quickstart - 5-minute setup
  • Guard Pattern - HITL approval flow
  • API Reference - All methods
  • Error Handling - Exception handling
  • Governance alignment - Operational evidence mapping

Legacy route aliases remain supported for existing installations, but new integrations should target the HaltState-branded public contract.

Legacy migration note

If upgrading from the legacy package/import namespace:

Existing code using the legacy import namespace continues to work, but new integrations should use from haltstate import ....

# Legacy (still works)
from janus import JanusClient, janus_guard

# New
from haltstate import HaltStateClient, haltstate_guard

Both import styles work - no code changes required for existing users.

License

MIT

Release files for haltstate-sdk 0.8.0.dev0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for haltstate-sdk 0.8.0.dev0
File Size Uploaded
haltstate_sdk-0.8.0.dev0.tar.gz 35.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for haltstate-sdk 0.8.0.dev0
File Interpreter ABI Platform
haltstate_sdk-0.8.0.dev0-py3-none-any.whl Python 3 none any Details

Total release size: 66.3 kB

Release files / haltstate_sdk-0.8.0.dev0.tar.gz

Download URL haltstate_sdk-0.8.0.dev0.tar.gz
Size 35.7 kB
Tags Source
SHA-256 checksum
How to use checksums
168757bbcf20a71d423a6b487c37a1a02af3f8590f2890e0e9ba026962d2c74f
BLAKE2b-256 checksum
How to use checksums
0ea6615c238e2c632eb0037c5b7d5bd3876ebbcc98f171b6d5f9c5c274ac5cd2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / haltstate_sdk-0.8.0.dev0-py3-none-any.whl

Download URL haltstate_sdk-0.8.0.dev0-py3-none-any.whl
Size 30.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e3c480de54327e9ef95dbbd664f83166582d2d3f00f5e81906b763e074913cf8
BLAKE2b-256 checksum
How to use checksums
fe3d328275cb7e746173a1431fc55a9b1712f704187b88d5064f42d8a77eade5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.8.0.dev0 This release

2 release files

0.7.0

2 release files

0.6.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page