Sentinel SDK
Oversight infrastructure for AI agents.
Sentinel adds human-in-the-loop approval to any Python function your agent calls.
Wrap the function with @oversight, and the SDK pauses execution, requests
approval, and only runs once a human approves.
Install
pip install sentinel-oversight
Quick start
# 1. Create an account at https://app.pauseapi.app/signup
# Copy the API key it returns.
# 2. Wrap your function:
from sentinel import configure, oversight
configure(api_key="sk_live_…")
@oversight(
risk_level="high",
approvers=["sms:+15551234567", "alice@acme.com"],
timeout_seconds=300,
)
def transfer_funds(amount: int, recipient: str):
return stripe.transfers.create(amount=amount, destination=recipient)
When your agent calls transfer_funds(1000, "acct_xyz"):
- Sentinel pauses execution and creates an approval on the backend.
- Notifications fire to every approver in the list (rules below).
- A human clicks Approve from a signed text/email link or the dashboard.
- The wrapped function runs, and its return value flows back to the caller.
If rejected → ApprovalRejected(reason) is raised. If no response within
timeout_seconds → ApprovalTimeout is raised (unless fallback="execute").
Approver formats
Each entry in approvers=[...] is a string. The format determines the channel.
| Format | Channel | Example |
|---|---|---|
name@company.com |
alice@acme.com |
|
mailto:name@company.com |
Email (explicit) | mailto:alice@acme.com |
sms:+15551234567 |
SMS (Twilio) | sms:+14155550123 — requires consent, see SMS approvers |
You can mix formats — every approver receives a notification, the first decision wins.
Notification routing
- Email — fires if
RESEND_API_KEYis set AND any approver looks like an email address. Email contains signed approve/reject links (HMAC-SHA256, scoped to that action_id and timeout window). - SMS — fires if Twilio credentials are set AND an approver uses
sms:.
By default, emails send from onboarding@resend.dev. To get branded
approvals@yourdomain.app email, verify your domain in Resend (Pro plan).
SMS approvers — TCPA consent
To use sms:+1... approvers you must first register an opt-in record for each
phone number. Sentinel won't create an approval whose approvers include an
SMS destination without an active consent record — the API returns
400 SMS approver requires active SMS consent contact.
from sentinel import SentinelClient
client = SentinelClient()
# One-time, per phone number, after you've collected a real opt-in:
client.register_sms_contact(
phone_number="+15551234567",
display_name="Maya (CTO)",
consent_source="onboarding_checkbox", # e.g. "signed_form", "captured_web_form"
consent_note="Checked the SMS opt-in box during signup on 2026-05-25",
)
Other helpers:
client.list_sms_contacts() # all active + revoked contacts for this tenant
client.revoke_sms_contact("con_…") # marks consent revoked; future SMS won't send
The customer can also reply STOP to any Sentinel SMS — the Twilio inbound
webhook (/webhooks/twilio/inbound) automatically revokes their consent
record. HELP returns a description and contact info. These two keywords
are TCPA-mandated.
Default approvers
If you don't want to pass approvers=[...] on every decorator, set a default
on your tenant. The API falls back to the tenant's default_approvers when
the caller's list is empty.
from sentinel import SentinelClient
client = SentinelClient()
client.set_default_approvers(["sms:+15551234567", "ops@yourcompany.com"])
# now any @oversight(...) call without approvers uses these
Read or override via the web UI at https://app.pauseapi.app/contacts.
Resolution order when an approval is created:
- The caller's explicit
approvers=[...](if non-empty) - The tenant's saved
default_approvers - The global
DEFAULT_APPROVERSenv var on the API - 400 error if all three are empty
Risk levels
risk_level is a string the dashboard uses for prioritization. Allowed values:
low, medium, high, critical. Required.
Configuration
Set via configure(...) or environment variables:
| Variable | Default | Description |
|---|---|---|
SENTINEL_API_URL |
https://api.pauseapi.app |
Base URL of the Sentinel backend |
SENTINEL_API_KEY |
required | Your tenant API key |
SENTINEL_TIMEOUT |
300 |
Default timeout_seconds |
SENTINEL_POLL_INTERVAL |
2 |
Seconds between status polls |
SENTINEL_FALLBACK |
reject |
reject or execute on timeout |
Exceptions
SentinelError— base class for all Sentinel errors.SentinelConfigError— SDK was used without anapi_key.SentinelAPIError(status_code, message, url)— backend returned a non-2xx.ApprovalRejected(reason, action_id)— a human rejected the request.ApprovalTimeout(action_id, timeout_seconds)— no decision before deadline.
Async
The decorator transparently supports async def functions:
@oversight(risk_level="medium", approvers=["alice@acme.com"])
async def send_email(to, body):
await mailgun.send(to=to, body=body)
Audit log
Every approval creates a hash-chained audit trail. Fetch it:
from sentinel import SentinelClient
client = SentinelClient()
events = client.list_audit_events(action_id="act_…") # or omit for full log
Each event has prev_hash and event_hash (SHA-256). Chain integrity can be
verified by recomputing sha256(prev_hash + json(payload)).
LangChain
from sentinel.adapters.langchain import SentinelCallbackHandler
agent.run("…", callbacks=[SentinelCallbackHandler(risk_level="high")])
Install with pip install sentinel-oversight[langchain].
Links
- Website: https://pauseapi.app
- Dashboard: https://app.pauseapi.app
- API repo: https://github.com/PetrefiedThunder/sentinel-api
- This SDK: https://github.com/PetrefiedThunder/sentinel-sdk
License
MIT
Metadata
Release files for sentinel-oversight 0.1.9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sentinel_oversight-0.1.9.tar.gz | 14.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sentinel_oversight-0.1.9-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.1 kB
Release files / sentinel_oversight-0.1.9.tar.gz
| Download URL | sentinel_oversight-0.1.9.tar.gz |
|---|---|
| Size | 14.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f36f1517666a0e7474d0a5755a13996269c70fb0b00f33cec419aa6ca255e282
|
|
BLAKE2b-256 checksum How to use checksums |
7d22e67db9fd15019210fb612000109eed1d14885467b175a8b8cd8643ad3180
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 May 26, 2026.
Transparency logRelease files / sentinel_oversight-0.1.9-py3-none-any.whl
| Download URL | sentinel_oversight-0.1.9-py3-none-any.whl |
|---|---|
| Size | 15.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
454d1e49872162633c6bde3da13faa19cc4abfa9ed8b3368914dc381f4ac1e41
|
|
BLAKE2b-256 checksum How to use checksums |
33f2d1c5abc9c241e8c0b0138ed577e7cb83241a470429beba50132e028af69f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 May 26, 2026.
Transparency log