Python SDK (vigil-sdk)
Sync and async clients, every route in the API, typed errors, three attempts with jittered backoff on 429 and 5xx, and a gate you have to opt out of honoring.
Install
pip install -e sdk/python # from the repo; PyPI publication is not set up
Emit and honor
from vigil import Vigil, HeldOutput
vg = Vigil(api_key="vg_...") # base_url defaults to https://vigil.supertruth.ai
vg.register_agent("jaybot", "JayBot", exist_ok=True)
gate = vg.emit("jaybot", "output_generated", {"content_length": 812}, dti=0.9, actor="agent:jaybot")
try:
gate.honor() # raises HeldOutput on hold, alert, collapse
except HeldOutput as h:
action = vg.wait_for_release(h.action_id, timeout=600) # polls GET /enforcement/{id} every 5s
if action["review_outcome"] != "released":
raise
gate.honor(allow_propagation=True) lets the output through but first emits an output_generated event with source: "vigil" and payload {"gate_ignored": true, "action_id": ..., "gate_status": ...}. Overriding the gate is itself on the ledger.
Async
from vigil import AsyncVigil
async with AsyncVigil(api_key="vg_...") as vg:
gate = await vg.emit("jaybot", "output_generated", {"content_length": 812})
await gate.honor()
Surface
| Method | Route |
|---|---|
register_agent(agent_id, name, description=None, exist_ok=False) | POST /agents/ |
get_agent, list_agents, set_monitoring(agent_id, monitored) | GET /agents/{id}, GET /agents/, PATCH /agents/{id}/monitoring |
emit(agent_id, event_type, payload, dti=None, source=None, actor=None) | POST /events/ |
get_trust(agent_id, dti=None), score_history | GET /scores/{id}/latest, /history |
audit(agent_id, limit=100), verify(agent_id), export_ledger(since_seq, limit) | GET /audit/... |
pending, get_action, latest_action, wait_for_release(action_id, timeout, interval) | GET /enforcement/... |
me(), usage(days) | GET /orgs/me, GET /usage |
create_key, list_keys, revoke_key | /keys/ (admin) |
list_scenarios, run_scenario | /test/... (review) |
Errors
VigilAuthError (401, 403), VigilNotFound (404), VigilRateLimited (429 after retries), VigilUnavailable (5xx after retries or no answer), VigilTimeout (wait_for_release), HeldOutput (honor()). All subclass VigilError, which carries .status and .detail. A 409 from register_agent is a plain VigilError unless exist_ok=True.
Testing your integration
Pass transport=httpx.ASGITransport(app=...) (async) or an httpx.MockTransport (sync) to the constructor, and backoff=0 to skip the retry sleeps. tests/test_sdk_python.py in the repo shows both.
Run it against your org
The same three calls the SDK makes, with the standard library only, so this runs anywhere Python 3 runs:
python3 - <<'EOF'
import json, os, urllib.request
url, key = os.environ["VIGIL_URL"], os.environ["VIGIL_KEY"]
def call(method, path, body=None):
req = urllib.request.Request(url + path, method=method, data=json.dumps(body).encode() if body else None,
headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"})
try:
with urllib.request.urlopen(req, timeout=20) as r: return r.status, json.load(r)
except urllib.error.HTTPError as e: return e.code, json.load(e)
s, _ = call("POST", "/agents/", {"agent_id": "docs-python", "name": "Docs Python"}); assert s in (200, 201, 409), s
s, gate = call("POST", "/events/", {"agent_id": "docs-python", "event_type": "output_generated", "payload": {"content_length": 640}, "dti": 0.9, "source": "self"})
assert s == 200, (s, gate)
print("gate", gate["gate_status"], "bii", gate["bii"], "action", gate["action_id"])
s, trust = call("GET", "/scores/docs-python/latest"); assert s == 200, s
print("latest bii", trust["bii"])
EOF