Skip to main content

Sentinel SDK for Python — the independent action-gate client for AI agents. Stdlib only, fails closed.

Project description

Sentinel

Sentinel SDK — Python

The stdlib-only Python client for the Sentinel action-gate.
Drop it at your agent's action boundary — fail-closed by default.

pypi python versions zero dependencies license Montana Labs

montanalabs-sentinel is a thin, dependency-free (stdlib-only) client placed at the action boundary inside your Python agent. It submits a proposed action to the Sentinel sidecar and returns the verdict. The sidecar — not the client — renders and signs the decision; if the sidecar is unreachable the client fails closed by default (it never silently lets an action through).

Install

pip install montanalabs-sentinel            # once published
# or from source:
pip install ./sentinel-sdks/python

Requires Python ≥ 3.9. No third-party dependencies.

Quick start

from montanalabs_sentinel import SentinelClient, Action

sentinel = SentinelClient("http://localhost:4000")

action = Action.payment({"amount": 42000, "from": "acct_ops", "to": "vendor_42"})
context = {"runId": run_id, "provider": "anthropic", "model": "claude-sonnet-4-6",
           "actor": {"id": "agent-007", "roles": ["ops"]}}

decision = sentinel.guard(action, context, "fintech.payments")

if decision.allowed:
    execute_payment(action)                 # only runs on ALLOW
elif decision.verdict == "ESCALATE":
    queue_for_review(decision.escalation_id)
else:
    log.warning("blocked: %s", decision.reason)   # BLOCK

API

SentinelClient(endpoint, fail_mode="closed", timeout=5.0, headers=None, transport=None)

Arg Type Default Notes
endpoint str Sidecar base URL, e.g. http://localhost:4000
fail_mode "closed" | "open" "closed" Transport failure → closed=BLOCK, open=ALLOW
timeout float (seconds) 5.0 Request timeout (treated as a transport failure)
headers dict[str,str] None Extra headers (e.g. auth to the sidecar)
transport callable urllib Inject for tests: (url, body, headers, timeout) -> (status, bytes)

guard(action, context, policy) -> GuardDecision

@dataclass
class GuardDecision:
    verdict: str           # "ALLOW" | "BLOCK" | "ESCALATE"
    record_id: str         # id of the signed provenance record ("" on transport fallback)
    checks: list[dict]     # per-check results
    reason: str | None
    escalation_id: str | None   # present when verdict == "ESCALATE"

    @property
    def allowed(self) -> bool:  # True only for ALLOW

SentinelClient.allowed(decision) is also available as a static method.

Building actions & context

Action.payment({"amount": 100, "from": "a", "to": "b"})            # typed helper
Action.of("record_update", {"patientId": "p1", "field": "note", "value": "…"}, id=None, meta=None)

# context (a plain dict) — the model trace behind the action
{"runId": "...", "provider": "...", "model": "...", "actor": {"id": "...", "roles": ["..."]}, "tenant": "..."}

Fail modes

  • closed (default): sidecar unreachable/erroring → guard returns a synthetic BLOCK with a sentinel.transport check, so your if decision.allowed: naturally prevents the action.
  • open: returns a synthetic ALLOW with a transport warning — only where availability outranks control.

guard never raises on transport problems; it always returns a GuardDecision.

Testing

Inject transport to test without a network:

def fake(url, body, headers, timeout):
    return 200, b'{"verdict":"ALLOW","recordId":"r","checks":[]}'

client = SentinelClient("http://x", transport=fake)
assert client.guard(Action.payment({}), {"runId": "r"}, "p").allowed

Run the tests

cd sentinel-sdks/python
PYTHONPATH=. python3 -m unittest discover -s tests -v

See also

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

montanalabs_sentinel-1.0.0.tar.gz (11.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

montanalabs_sentinel-1.0.0-py3-none-any.whl (11.2 kB view details)

Uploaded Python 3

File details

Details for the file montanalabs_sentinel-1.0.0.tar.gz.

File metadata

  • Download URL: montanalabs_sentinel-1.0.0.tar.gz
  • Upload date:
  • Size: 11.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for montanalabs_sentinel-1.0.0.tar.gz
Algorithm Hash digest
SHA256 0c9009d4dfd5bf6a7b4c1e971c0a725fa900951ce6b55966c675c0b6ec4828f2
MD5 d1ec452fd57185c1767f865cc4648df8
BLAKE2b-256 119859fb4e3001cead9cb2aea9f26530008897f6e15d808ea288133200bd2c89

See more details on using hashes here.

Provenance

The following attestation bundles were made for montanalabs_sentinel-1.0.0.tar.gz:

Publisher: publish-pypi.yml on Montanalabs/sentinel-sdks

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file montanalabs_sentinel-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for montanalabs_sentinel-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bfc46a9b56b90244ac5c8798ef406c866e02f8b967f778efb7f50a94937dd807
MD5 42aef85968e33808703c6cdf3af18b8e
BLAKE2b-256 3a5dc77c7d46144d6ed578f61c519253ee2e84bc74e221448b0c62b13a8745c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for montanalabs_sentinel-1.0.0-py3-none-any.whl:

Publisher: publish-pypi.yml on Montanalabs/sentinel-sdks

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page