DBDelve
Dive deep into your data. A fast, native, multi-engine database client written in Rust. Free and open source, no telemetry.
Human-in-the-loop approval, hash-chained audit log, and oversight infrastructure for AI agents.
Developer toolsPythonGitHub @PetrefiedThunderOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Python SDK for Sentinel: human approval and review for AI agent actions (PyPI: sentinel-oversight).
Loading the full README.
Read the full README ↗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.
pip install sentinel-oversight
# 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", "[email protected]"],
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"):
If rejected → ApprovalRejected(reason) is raised. If no response within
timeout_seconds → ApprovalTimeout is raised (unless fallback="execute").
Each entry in approvers=[...] is a string. The format determines the channel.
| Format | Channel | Example |
|---|---|---|
[email protected] | [email protected] | |
mailto:[email protected] | Email (explicit) | mailto:[email protected] |
sms:+15551234567 | SMS (Twilio) | sms:+14155550123 — requires consent, see SMS approvers |
You can mix formats — every approver receives a notification, the first decision wins.
RESEND_API_KEY is 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:.By default, emails send from [email protected]. To get branded
[email protected] email, verify your domain in Resend (Pro plan).
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.
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", "[email protected]"])
# 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:
approvers=[...] (if non-empty)default_approversDEFAULT_APPROVERS env var on the APIrisk_level is a string the dashboard uses for prioritization. Allowed values:
low, medium, high, critical. Required.
Pass idempotency_key to safely retry approval creation. The same tenant + key
replays the original response; reusing a key with a different body returns 409.
client.create_approval(
function_name="transfer_funds",
arguments={"amount": 100},
idempotency_key="transfer-2026-06-09-001",
)
@oversight(idempotency_key=...) also accepts a callable, invoked once per call.
Set via configure(...) or environment variables:
This is the beginning of the README. Read the rest at the original. Read the full README ↗