Documentation home

Python SDK

First-party Python SDK for server-side agents, scheduled workers, and async services.

Status

First-party Python SDK
Status: Beta
Package: haltstate-sdk
Published: 0.7.0
Replay-safe source candidate: 0.8.0.dev0 (not yet published). Install the reviewed repository source for the candidate contract.

Client

from haltstate import HaltStateClient

client = HaltStateClient(
    tenant_id=os.environ["HALTSTATE_TENANT_ID"],
    api_key=os.environ["HALTSTATE_API_KEY"],
)

Context manager guard

operator_epoch = "11111111-2222-4333-8444-555555555555"
destination_key = "refund:lge_123"
guard_key = f"hsr1:{operator_epoch}:{destination_key}"
report_id = "40000000-0000-4000-8000-000000000501"

with client.guard(
    "refund.create",
    params={"amount": 89, "currency": "USD"},
    idempotency_key=guard_key,
    report_id=report_id,
) as permit:
    permit.validate_for_execution()
    ledger.execute_refund(idempotency_key=destination_key)

Service pattern

The context manager reports both success and error with the caller-stable report_id. Long-running workers should persist the exact permit and report envelope before an uncertain retry, then call the public report_guard_outcome recovery API without rerunning the destination action. If HaltState is unavailable for a high-risk action, the worker should fail closed.

Sync check and report

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='refund.create',
    params={'amount': 126, 'currency': 'USD'},
    agent_id='retail-refund-agent',
)

if decision.allowed:
    result = execute_refund_once()
    client.report(decision, status='success', result=result, action='refund.create', agent_id='retail-refund-agent')
elif decision.requires_approval:
    mark_pending()
else:
    mark_denied(decision.reason)

Async check pattern

from haltstate import AsyncHaltStateClient

async def process_payment(invoice_id: str, amount: int):
    async with AsyncHaltStateClient(tenant_id='acme', api_key='hs_xxx', base_url='https://haltstate.ai') as client:
        decision = await client.check(
            action='payment.process',
            params={'invoice_id': invoice_id, 'amount': amount},
            agent_id='payment-bot',
        )
        if decision.allowed:
            result = await execute_payment(amount)
            await client.report(decision, status='success', result={'ok': True}, action='payment.process', agent_id='payment-bot')
            return result
        if decision.requires_approval:
            return {'status': 'pending'}
        return {'status': 'denied', 'reason': decision.reason}

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)

Use decorators for small service methods where the action name and idempotency key are obvious. Use explicit guard blocks for workers that need ledger transitions, Proof Packs, and multi-step reporting.

Exception imports

from haltstate import (
    HaltStateError,
    HaltStateAuthError,
    HaltStateConnectionError,
    HaltStateRateLimitError,
    ApprovalPending,
    ActionDenied,
    ActionExpired,
)

Compatibility namespace

Existing code using the earlier import namespace can continue to work, but new integrations should use from haltstate import .... The compatibility path is for migration, not for new public examples.

Replay-safe source candidate contract

The stable retry identity binds the exact agent, action or tool, resource, normalized parameters, risk class, and immutable policy version. With an operator-issued activation epoch, the SDK may create epoch-qualified generated keys only when the caller omitted a key; explicit keys are never changed. Approval expiry blocks a stale permit, while already_started and completed remain terminal. After the side effect, receipt validation requires the durable event ID, receipt hash, received flag, and duplicate marker; retry the same report identity without rerunning the action.

This is a source candidate contract, not evidence that the candidate package is registry-published or production-deployed. Published package baselines and language-specific executable verification status are listed separately above.

Implementation notes

Keep the HaltState call as close as possible to the side effect. The agent may plan and draft freely, but the wrapper around the actual action should be the place where authority is checked. That wrapper should send only the context required for policy evaluation: safe identifiers, normalized amounts, action names, risk flags, schedule windows, and redaction status. Raw customer payloads and secrets should stay in the business system or protected operator tooling.

Operational evidence

For each action, preserve the decision, the worker outcome, the idempotency key, safe resource references, latency, proof status, and redaction status. This evidence supports incident response and control narratives because it shows what the system did at runtime rather than only describing what the policy document intended. HaltState supports alignment work; it is not a substitute for legal advice or a compliance certification.