Primitive Python client for Relivio deploy registration, ingest, and exception capture.
- current package scope:
0.2.0 - supported Python versions:
3.9+ - current public surface:
deployments.register()deployments.register_from_environment()ingest.send()ingest.asend()ingest.send_batch()capture_exception()acapture_exception()protection.get_status()verdicts.latest()status()
- automatic retry only for
429 RATE_LIMITED
- full verdict consumer surface
- feedback/history/list/search APIs
- guard or middleware implementation
- broad auto instrumentation or metric collection
- framework adapters
- request object parsing
pip install relivioVerify the installed package:
python -c "import relivio; print(relivio.__all__)"For local development:
pip install -e ".[dev]"from relivio import Relivio, IngestLogInput
relivio = Relivio(api_key="rk_...")
deployment = relivio.deployments.register()
print(deployment.deployment_id)
result = relivio.ingest.send(
IngestLogInput(
level="ERROR",
message="checkout failed",
api_path="/api/orders/finalize",
)
)
print(result.log_event_id)
verdict = relivio.verdicts.latest()
if verdict is not None:
print(verdict.verdict, verdict.decision_tier)Capture exceptions explicitly from the boundary that already knows the safe path/context:
try:
run_usecase()
except Exception as exc:
relivio.capture_exception(
exc,
service="checkout-api",
api_path="/api/orders/{id}",
trace_id="req_123",
)
raiseIf service and trace_id are repetitive across calls, set them once at client init. They apply only to capture_exception / acapture_exception — explicit ingest.send() payloads are passed through unchanged.
import contextvars
from typing import Optional
request_id_var: contextvars.ContextVar[Optional[str]] = contextvars.ContextVar(
"request_id", default=None
)
relivio = Relivio(
api_key="rk_...",
default_service="checkout-api",
trace_id_provider=request_id_var.get, # called per capture; exceptions are swallowed
)
# Per-call only api_path needs to be passed.
relivio.capture_exception(exc, api_path=request.path)Read protection status explicitly from guard code:
from relivio import ProtectionStatusInput
status = relivio.protection.get_status(
ProtectionStatusInput(
service="checkout-api",
api_path="/api/orders/{id}",
method="POST",
)
)
print(status.decision_tier, status.matched_api_path)import asyncio
from relivio import Relivio, RegisterDeploymentInput
relivio = Relivio(api_key="rk_...")
async def main() -> None:
deployment = await relivio.deployments.aregister(
RegisterDeploymentInput(version="1.2.3")
)
print(deployment.deployment_id)
try:
await run_usecase()
except Exception as exc:
await relivio.acapture_exception(
exc,
service="checkout-api",
api_path="/api/orders/{id}",
)
raise
asyncio.run(main())python -m venv .venv
./.venv/bin/pip install -e ".[dev]"
./.venv/bin/pytest
./.venv/bin/python -m build- API key is sent through
X-API-Key Idempotency-Keyis supported for v0 writer endpoints- 429 responses are retried with
Retry-After - 5xx responses are not retried
- server can accept gzip payloads, but SDK v0 sends plain JSON only
- SDK code never receives framework request objects
capture_exception()is an ingest helper, not a framework adaptercapture_exception()swallows Relivio delivery failures and records them in localstatus()protection.get_status()is a thin read over/api/v1/protection/status; it does not make block/allow decisionsverdicts.latest()is intentionally narrow and only exists to support service-side guard logicverdicts.latest()returnsNoneon 404 when a verdict is not available yetstatus()reports SDK self-diagnostics locally; it does not send host metrics to Relivio
relivio-server: server-side deploy registration, ingest, and summary generationrelivio-mcp: agent-facing verdict consumer surface
Do not commit project API keys. Keep X-API-Key values in environment variables or local secret storage outside source control.
Small, behavior-preserving changes are preferred. Keep transport, resource, type, and error responsibilities separate, and run the smallest effective test/build checks before sending a change.