irl-sdk — Python SDK for the IRL Engine
Async Python client for the IRL Engine — the cryptographic pre-execution compliance gateway for autonomous AI trading agents.
- Optionally fetches a signed Layer 2 heartbeat from a regime operator (MTA), when your IRL server uses one
- Constructs and signs the authorize request
- Returns a sealed
trace_idandreasoning_hashbefore any order reaches the exchange
What's new in 0.3.0
- No regime operator required:
mta_urlis optional. Without it the SDK sends no heartbeat, which is what an IRL server withMTA_MODE=none(agent caps only) expects.IRLClient(IRL_URL, API_TOKEN)is enough. - Retry + circuit breaker: All API calls retry on 5xx responses with exponential backoff (default: 3 retries, 0.5 s base delay). Configurable via
max_retriesandbackoff_base. - Multi-agent trace linking:
AuthorizeRequest.parent_trace_idlinks a sub-agent call to its orchestrator, enabling full causal chain audits viaget_trace_chain(). - Extended order types:
OrderTypenow includesVWAP,IOC,FOK,POST_ONLY,PEGGED,TRAILING_STOP,ICEBERG. bind_execution()+get_trace()+get_trace_chain(): Full post-trade and audit chain methods.
Install
pip install irl-sdk
Requires Python 3.10+.
Quick Start
import asyncio
from irl_sdk import IRLClient, AuthorizeRequest, TradeAction, OrderType
IRL_URL = "https://norve.dev"
API_TOKEN = "your-irl-api-token"
AGENT_ID = "your-agent-uuid" # from POST /irl/agents
MODEL_HASH = "your-model-sha256-hex" # 64-char hex
async def main():
async with IRLClient(IRL_URL, API_TOKEN) as client:
req = AuthorizeRequest(
agent_id=AGENT_ID,
model_id="my-model-v1",
model_hash_hex=MODEL_HASH,
action=TradeAction.LONG,
asset="BTC-USD",
order_type=OrderType.MARKET,
venue_id="coinbase",
quantity=0.1,
notional=6500.0,
notional_currency="USD",
)
result = await client.authorize(req)
if result.authorized:
print(f"AUTHORIZED trace_id={result.trace_id}")
print(f"reasoning_hash={result.reasoning_hash[:24]}...")
# embed trace_id in your exchange order metadata, then place the order
else:
print("HALTED — IRL blocked the trade")
asyncio.run(main())
End-to-End Demo
The demo registers nothing — it uses a pre-seeded demo agent in the public sandbox:
cd examples
pip install -e ..
python demo_e2e.py
Expected output:
IRL Engine : https://norve.dev
MTA : https://api.macropulse.live
Agent ID : 00000000-0000-4000-a000-000000000001
Fetching heartbeat and submitting authorize request...
AUTHORIZED
trace_id : <uuid>
reasoning_hash: <first 24 chars>...
shadow_blocked: False
API Reference
IRLClient(irl_url, api_token, mta_url, timeout, max_retries, backoff_base)
Async context manager. All parameters are positional.
| Parameter | Type | Default | Description |
|---|---|---|---|
irl_url |
str | — | IRL Engine base URL |
api_token |
str | — | Bearer token (from IRL_API_TOKENS env on the engine) |
mta_url |
str | None | None |
Regime operator (MTA) URL. Set it only if your IRL server has LAYER2_ENABLED=true; the SDK then fetches a fresh signed heartbeat per call. Unset or "" sends no heartbeat. |
timeout |
float | 5.0 |
HTTP request timeout in seconds |
max_retries |
int | 3 |
Max retry attempts on 5xx responses |
backoff_base |
float | 0.5 |
Base delay (seconds) for exponential backoff between retries |
client.authorize(req: AuthorizeRequest) → AuthorizeResult
- If
mta_urlis set, fetches a fresh signed heartbeat from{mta_url}/v1/irl/heartbeat - POSTs to
{irl_url}/irl/authorizewith the request payload (and the heartbeat, if any) - Returns
AuthorizeResult
AuthorizeRequest fields
| Field | Type | Required | Notes |
|---|---|---|---|
agent_id |
str | yes | UUID registered via POST /irl/agents |
model_id |
str | yes | Human-readable model name |
model_hash_hex |
str | yes | SHA-256 of model config (64 hex chars) |
action |
TradeAction | yes | LONG / SHORT / NEUTRAL |
asset |
str | yes | e.g. "BTC-USD", "SPY" |
order_type |
OrderType | yes | MARKET / LIMIT / STOP / TWAP / VWAP |
venue_id |
str | yes | Exchange identifier |
quantity |
float | yes | Order size |
notional |
float | yes | Notional value |
notional_currency |
str | yes | e.g. "USD" |
client_order_id |
str | no | Your internal order reference |
agent_valid_time |
int | no | Model inference timestamp (ms). Defaults to now. |
parent_trace_id |
str | no | trace_id of the orchestrator decision that triggered this sub-agent call. Enables get_trace_chain() causal audits. |
AuthorizeResult fields
| Field | Type | Notes |
|---|---|---|
trace_id |
str | UUID — embed in exchange order metadata |
reasoning_hash |
str | SHA-256 seal of the full cognitive snapshot |
authorized |
bool | True = proceed; False = halted by policy |
shadow_blocked |
bool | True = would have been blocked; only set when SHADOW_MODE=true on the engine |
TradeAction
from irl_sdk import TradeAction
TradeAction.LONG # "Long"
TradeAction.SHORT # "Short"
TradeAction.NEUTRAL # "Neutral"
OrderType
from irl_sdk import OrderType
OrderType.MARKET # "MARKET"
OrderType.LIMIT # "LIMIT"
OrderType.STOP # "STOP"
OrderType.TWAP # "TWAP"
OrderType.VWAP # "VWAP"
OrderType.IOC # "IOC"
OrderType.FOK # "FOK"
OrderType.POST_ONLY # "POST_ONLY"
OrderType.PEGGED # "PEGGED"
OrderType.TRAILING_STOP # "TRAILING_STOP"
OrderType.ICEBERG # "ICEBERG"
client.get_trace_chain(trace_id: str) → dict
Returns the full causal ancestry chain for a trace. Useful for multi-agent audit trails where sub-agent decisions trace back to an orchestrator.
chain = await client.get_trace_chain(result.trace_id)
# {"trace_id": "...", "ancestry": [...], "children": [...]}
Error Handling
The SDK raises httpx.HTTPStatusError on non-2xx responses. The response body
contains {"error": "ERROR_CODE", "message": "..."}. Common codes:
| Code | Meaning |
|---|---|
HEARTBEAT_DRIFT_EXCEEDED |
Heartbeat too old — clock skew or slow network |
HEARTBEAT_MTA_REF_MISMATCH |
MTA hash mismatch — regime changed between heartbeat and authorize |
REGIME_VIOLATION |
Action not permitted in current regime |
NOTIONAL_EXCEEDS_LIMIT |
Exceeds agent notional cap × regime scale |
MODEL_HASH_MISMATCH |
Provided hash ≠ registered hash |
AGENT_NOT_FOUND |
Register the agent first via POST /irl/agents |
Layer 2 (Heartbeat) Details
Only relevant when the engine runs with a regime operator and LAYER2_ENABLED=true:
every authorize request must then carry a SignedHeartbeat, which the SDK fetches
from {mta_url}/v1/irl/heartbeat when you pass mta_url.
The heartbeat binds each request to a specific MTA broadcast:
sequence_id— strictly monotone (anti-replay)timestamp_ms— must be withinMAX_HEARTBEAT_DRIFT_MSoftxn_timemta_ref— SHA-256 of the raw/v1/regime/currentHTTP response bodysignature— Ed25519 signature by the MTA operator
With MTA_MODE=none or LAYER2_ENABLED=false (the public IRL server runs this way),
leave mta_url unset: no heartbeat is sent and only the agent's own mandate applies.
Ecosystem
| Repo | Description |
|---|---|
| irl | Core IRL Engine (FSL-1.1-ALv2) |
| irl-gateway | MCP server: AI agents trade through IRL (pip install irl-gateway) |
| irl-sdk-ts | TypeScript/Node.js SDK |
| irl-public-docs | Public documentation hub |
| MacroPulse | One optional signed regime source (MTA) |
License
MIT
Metadata
Release files for irl-sdk 0.3.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 |
|---|---|---|---|---|
| irl_sdk-0.3.0.tar.gz | 12.6 kB | With provenance | Details for irl_sdk-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| irl_sdk-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for irl_sdk-0.3.0-py3-none-any.whl |
Total release size: 21.4 kB
Release files / irl_sdk-0.3.0.tar.gz
| Download URL | irl_sdk-0.3.0.tar.gz |
|---|---|
| Size | 12.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c01a6c49131caa21d89028911f4200e3cab99ca0aba62f77debd48963c97791c
|
|
BLAKE2b-256 checksum How to use checksums |
b58d21ceaa0d8feb137064b7f710952771719b3fe9bf30f251e3bc7819377352
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency logRelease files / irl_sdk-0.3.0-py3-none-any.whl
| Download URL | irl_sdk-0.3.0-py3-none-any.whl |
|---|---|
| Size | 8.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
528bdf3b291501585379fd3c859628290329dc3eb979b4df5020878a884500a9
|
|
BLAKE2b-256 checksum How to use checksums |
4b2c0af5bc639db0d27753bb15d5c2d183d6499da0249fdb86abd2b22377f961
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency logSecurity for irl-sdk 0.3.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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for irl_sdk-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency logA 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.