Skip to main content

sentisec-sdk

Public Python SDK for Sentisec.

sentisec-sdk is a thin client. You install it with pip, point it at your workspace, and wrap your existing OpenAI / Anthropic client. Your agent's tool calls then flow through Sentisec's hosted control plane, where they are evaluated and either allowed, rewritten, or blocked before they reach the world.

Install

pip install sentisec-sdk

Python 3.11+ is required.

Quick start

from sentisec_sdk import Monitor

monitor = Monitor()  # picks up ~/.sentisec/credentials.toml after `sentisec login`
client = monitor.wrap_openai(...)
client = monitor.wrap_anthropic(...)

The sentisec CLI is shipped in the same wheel — see The sentisec CLI below for the full surface.

sentisec login
sentisec status
sentisec demo run
sentisec logout

sentisec login always prints its pairing URL to stderr before waiting. If no browser opens, open that URL yourself. sentisec login --print-url-only skips browser launch and waits up to 120 seconds on a real local callback port; successful pairing saves credentials just like ordinary login. The browser must reach this machine's localhost. To pair from a browser on another machine, copy a pairing code from the dashboard and run sentisec login --code <code> on the machine you are pairing.

From 0.1.0a4 onwards SENTISEC_WORKSPACE_ID is OPTIONAL — the Sentisec proxy resolves the workspace from the API key prefix, so a one-env-var setup (SENTISEC_API_KEY only) is sufficient for the wrap_anthropic / wrap_openai path.

Corrected 2026-08-18: this section used to warn that Monitor() / Session() "raises NotImplementedError" in the alpha. That has not been true since 0.1.0a0 — the wrapper path is fully implemented and tested. The note is removed rather than softened; it described a build state, not the shipped wheel.

Protecting a Claude Code / Codex subscription (sentisec edge)

The same wheel ships the edge daemon — the way to put Sentisec in front of an agent you drive on a Claude or ChatGPT subscription, with no API key and no provider token ever leaving your machine.

sentisec edge            # guided setup: pair, install, start
sentisec edge status     # what is wired and whether it is healthy
sentisec edge off        # pause: calls pass through unchecked
sentisec edge on         # resume (also restarts the local service)
sentisec edge logs       # the local service log
sentisec edge uninstall  # remove the service, hooks and provider entry

Setup is re-runnable and refuses before it writes: it looks for Claude Code first, then verifies your workspace key with Sentisec, then shows every file it is about to change and asks once. For a headless install, pass --key (or set SENTISEC_WORKSPACE_KEY) with --yes:

sentisec edge setup --yes --key "$SENTISEC_WORKSPACE_KEY"

sentisec edge off is real: while it is paused the local service answers every Claude Code hook with an explicit "not checked" allow, relays Codex turns untouched, and uploads nothing.

Setup starts a small local service (launchd on macOS, a systemd user unit on Linux) listening on 127.0.0.1:45711. It forwards Claude Code's PreToolUse hooks to Sentisec's hosted control plane for a verdict and uploads a token-scrubbed activity trail. When Codex is wired it also listens on 45712 and relays each turn to chatgpt.com — your ChatGPT credential goes there and nowhere else, and the copy Sentisec analyses is redacted before it is sent. When Sentisec blocks a call in a Codex turn, Codex receives the turn with that call replaced by a sentisec_tool_call_blocked tool call and the other calls intact, in the turn's own form (streamed or not); a block Sentisec cannot rewrite refuses the turn.

No detection logic runs on your machine. The daemon forwards and enforces; the analysis happens server-side.

When the local service is stopped or hung

Claude Code's PreToolUse command hook asks the local service for a decision with a 10-second deadline. If the connection is refused, the service is hung, or its answer is unusable, the hook uses your explicit posture setting, then the workspace's remembered mode:

Remembered mode (no explicit override) Claude Code hook answer
enforcing (enforce, scoped_enforce) ask for approval
monitoring (shadow, observe) allow, marked as not checked
unknown ask for approval

An explicit open, ask or closed posture overrides that mode choice. A paused edge returns its explicit "not checked" allow. The hook has a 15-second host timeout; if its Python or sentisec executable cannot start, a shell fallback answers ask.

Run sentisec edge doctor to see the installed hook transport, host versions and a timed round trip through the hook. sentisec edge on restarts the local service. After upgrading Sentisec, sentisec edge on and sentisec edge status replace an existing legacy HTTP PreToolUse hook with the command hook, preserve your other hooks, and print one upgrade notice to stderr. Repeating either command leaves current hooks untouched. sentisec edge setup also installs the current hook.

When Sentisec cannot be reached

The daemon has to answer a tool call it is holding, even when Sentisec's hosted plane is unreachable. What it answers is yours to choose:

SENTISEC_EDGE_FAIL_POSTURE Claude Code Codex
open the call is allowed the turn is relayed
ask Claude Code prompts you the turn is held — Codex has no approval prompt, so it cannot be approved
closed the call is denied the turn is refused (HTTP 403)
(unset — the default) monitoring-only workspaces allow; enforcing and not-yet-known workspaces ask monitoring-only workspaces relay; enforcing and not-yet-known workspaces hold

The same value can live in ~/.sentisec/edge.toml as fail_posture = "…"; the environment variable wins, so you can change posture during an incident without editing a file the setup wizard also writes. The command hook reads SENTISEC_EDGE_FAIL_POSTURE from Claude Code's environment; the daemon reads it from its launchd or systemd service environment. Configure each environment where you want the override to apply; setting it in a terminal does not change an already-running Claude Code process or service.

Which workspace you belong to is remembered. Setup asks Sentisec (/v1/sdk/whoami), and Claude Code checks report it again. sentisec status, sentisec doctor and sentisec edge status also refresh the record when the edge workspace key receives a recognized mode from that live endpoint. The answer is stored in ~/.sentisec/enforcement-mode.json — the mode word, your workspace id, when it was learned and which call taught it, and nothing else. No key, no token, no request content ever goes in that file, it is written 0600, and sentisec edge uninstall removes it. It is what lets a restart, a reboot or a Codex-only install still know what you asked for. A record written for a different workspace is ignored rather than inherited.

The diagnostic commands report whether the record was refreshed. An offline, rejected, unavailable or invalid answer leaves it unchanged and says so; --offline on status/doctor also leaves it unchanged. A local write failure is reported separately. The CLI refresh takes effect at the daemon's next start: an already-running daemon keeps its process-local mode until its own authenticated check reports a mode. SDK login credentials can belong to a different workspace and never refresh the edge record.

A fresh boot with no usable mode record prompts on Claude Code when the gate cannot answer. Missing, unreadable, invalid or wrong-workspace records leave the mode unknown, which now resolves to ask on both arms: Claude prompts, while Codex continues to hold. Each unchecked Claude call may need approval, so unattended work can wait during a partition, even for a workspace that is actually monitoring-only but whose mode has not been learned. Setup, sentisec status and sentisec doctor seed the record when Sentisec can be reached; the daemon reads that record at its next start. An already-running daemon learns from its own authenticated gate answers. Known monitoring modes and explicit posture overrides are unchanged.

No key, no allow. A daemon with no workspace key — ~/.sentisec/edge.toml deleted, or setup never finished — sends nothing to Sentisec and answers every tool call by the same rule: an explicit posture, else the remembered mode (enforcing or unknown asks, monitoring allows); the Codex relay holds an enforcing or unknown workspace's turn. The reason names the missing key and sentisec edge setup. Deleting the file and restarting the daemon therefore does not switch checking off. (Earlier versions allowed every call with no key.)

On Codex, an unknown workspace is treated as an enforcing one. Codex's relay has no way to put an approval prompt in front of you mid-turn, so a turn that could not be checked is answered with a readable refusal — naming your workspace mode, what failed, and the one setting that releases it — instead of being passed through as if it had been checked. If you would rather have the turn than the check, set SENTISEC_EDGE_FAIL_POSTURE=open.

Whatever it decides, it records: every unchecked call leaves a event=edge_fail_posture_applied line in the daemon's log naming the cause, the posture and the decision, every held Codex turn leaves an event=edge_codex_turn_held line naming the workspace mode, and the activity trail marks the call as unchecked once connectivity returns.

The sentisec CLI

One command group, one exit-code contract, --json on everything that has something to report.

Command What it does
sentisec grouped help; names the two ways to get started
sentisec login / logout pair (or unpair) this machine with a workspace
sentisec status what this machine is connected to, and whether it works
sentisec doctor fifteen local checks, each with the fix on the line
sentisec demo run a scripted scenario against your workspace
sentisec update / version what is installed, and what is available
sentisec edge … cover a Claude Code / Codex subscription (above)

Exit codes. Every command uses the same seven:

Code Meaning
0 success
1 failure, or a configured thing is broken
2 usage
3 not configured / not authorised
4 network or endpoint
5 the verdict diverged from what the scenario expected
130 interrupted

Machine-readable output. --json prints exactly one JSON document on stdout and nothing else; every document carries schema_version and exit_code. Available on status, doctor, demo run, update, version, login, logout, edge status, edge setup --yes, edge on, edge off and edge uninstall. A workspace key never appears in any of them — only its last four characters.

Terminal behaviour. Colour is off under NO_COLOR, TERM=dumb, --no-color, --plain, and whenever stdout is not a terminal. --plain prints the same lines without panels, spinners or colour, with ASCII status markers. -q prints nothing and lets the exit code carry the answer.

Version check. status, doctor, version, update and the bare help may check for a newer release: one request, a one-second budget, cached for a day under ~/.sentisec/update-check.json, silent on failure, and never before the command's own output. Set SENTISEC_NO_UPDATE_CHECK=1 to switch it off. sentisec update only prints the upgrade command for however you installed the CLI; it never changes the installation itself.

Documentation

Building the standalone CLI

For shipping channels that cannot rely on a working pip on the user's box (curl installer, npm postinstall, GitHub Releases tarball), the sentisec console-script entry is bundled as a single shiv zipapp:

# one-time: install the build-only extra
uv pip install --system shiv          # or: pipx install shiv

# build
./scripts/build-cli.sh                # → dist/sentisec (executable)

# (optional) verify the build is reproducible
VERIFY_DETERMINISM=1 ./scripts/build-cli.sh

The build script:

  • runs shiv --console-script sentisec --output-file dist/sentisec --reproducible --compressed --python "/usr/bin/env python3" .,
  • smoke-tests ./dist/sentisec --version and asserts the output equals sentisec <version-from-pyproject>,
  • when VERIFY_DETERMINISM=1, rebuilds into a tempdir and diffs the two artifacts byte-for-byte (shiv's --reproducible flag pins all zip-entry timestamps to a fixed value).

Platform caveat. The resulting dist/sentisec shebangs to /usr/bin/env python3, but its bundled wheels include the native pydantic-core extension for the builder's (os, arch, python-minor) tuple. The artifact therefore runs on hosts matching that tuple only. The release pipeline (P-INST-02) matrix-builds one artifact per supported tuple and uploads each as a separate GitHub Release asset.

License

Apache License 2.0. See LICENSE.

Metadata

Release files for sentisec-sdk 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sentisec-sdk 1.0.0
File Size Uploaded
sentisec_sdk-1.0.0.tar.gz 214.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sentisec-sdk 1.0.0
File Interpreter ABI Platform
sentisec_sdk-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 459.5 kB

Release files / sentisec_sdk-1.0.0.tar.gz

Download URL sentisec_sdk-1.0.0.tar.gz
Size 214.1 kB
Tags Source
SHA-256 checksum
How to use checksums
a3df4cffe7557df721800724f849e3386ee43d1e54d5dbc607a411869705b71c
BLAKE2b-256 checksum
How to use checksums
9dc41de1b8e594f426efc7522914d52b10f161b94c728abe73e06c938711529a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 17, 2026.

Transparency log

Release files / sentisec_sdk-1.0.0-py3-none-any.whl

Download URL sentisec_sdk-1.0.0-py3-none-any.whl
Size 245.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1c0dde4a4437e8596709ad4c5b64d9191da0ca7b91788d0f9aa7cb30b508b44b
BLAKE2b-256 checksum
How to use checksums
e2700497d7456e2a5a1b90b826a5d11026e1bd0968e83c284c270f8b183bfcf0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 17, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page