Actrail
Runtime policies for AI agents — the open-source edge SDK
Govern what your agents do, not just what they say. Actrail captures every agent action's full tool-call arguments as telemetry and enforces deterministic policies before a risky action runs — a human-readable rule, never an LLM, in the binding decision.
Why Actrail
AI agents don't just generate text — they take actions: refund a customer, delete a row, deploy to prod, send data to an external LLM. Content guardrails don't see any of that. Actrail governs the actions:
- Deterministic enforcement. Policies are plain rules (`payment.transaction_amount
5000 → deny`) evaluated on a bounded request, fail-open by default. No model participates in the verdict.
- Value-aware policies. The SDK sends the tool call's full argument JSON — not a value-stripped skeleton — so a policy can be written against an actual argument value (an amount, a currency, a destination path), not just which fields exist.
- A thin edge. The SDK is a hook → span/check relay: it classifies a call's action and destination locally, then hands the backend the full picture. Redaction of credential-shaped values and PII classification are the backend's job now, not an edge heuristic — see Security & privacy.
Install
pip install actrail
Requirements
- Python 3.11+. The system Python on macOS is 3.9 and will not work — use a 3.11/3.12 environment.
- macOS 12+ (Apple Silicon or Intel) or Linux x86_64. Prebuilt wheels bundle the native shim — no toolchain needed.
Verify:
actrail --help # bundled CLI on PATH
python -c "import actrail; print(actrail.__version__)"
not a supported wheel on this platform? Almost always your Python isn't 3.11/3.12 (macOS ships 3.9). Create a 3.11/3.12 env — e.g.uv venv --python 3.12— and reinstall.
Quickstart
Claude Code (zero-code onboarding)
actrail init --key ak_live_... # registers the SDK, wires hooks, starts the daemon (shadow)
actrail doctor # verify config · hooks · daemon
init also registers this SDK release with the backend (metadata only —
integration/version/contract, no customer data), so Actrail can install the managed
policies this release is certified to enforce before the first trail arrives.
init wires the pre-tool policy check immediately. Policies still begin in shadow,
so nothing blocks until an administrator graduates one to enforce in the Actrail
console. actrail enforce off is an explicit local emergency opt-out; enforce on
restores the hook if it was removed.
Two managed catalog rules intentionally need organization-specific named sets before
they can govern: production_destructive_action needs prod_hosts, and
customer_data_unapproved_destination needs approved_destinations. Configure those
in the console during onboarding; the SDK never guesses tenant trust boundaries.
Any agent (the library)
import actrail
actrail.init(key="ak_live_...", agent="support-bot")
# Before a risky action — get a deterministic, bounded verdict.
verdict = actrail.check(
trail_id="sess_42",
tool="pay.api",
action="refund",
tool_input={"order": {"amount": 2500, "currency": "USD"}, "table": "prod.customers"},
)
if not verdict.allow:
raise PermissionError(verdict.reason) # require_approval / deny
# After it runs — capture the action as telemetry (fire-and-forget).
actrail.capture(
trail_id="sess_42",
tool="pay.api",
action="refund",
tool_input={"order": {"amount": 2500}, "customer": {"email": "alice@example.com"}},
)
tool_input is the full tool-call argument JSON, exactly as your integration (or
Claude Code) produced it. Actrail sends it on the wire, bounded only by size (see
What leaves the machine) — the backend is where it's
governed: bounded and redacted server-side, and turned into the policy-queryable
fields a custom rule like "deny refund_payment when payment.transaction_amount >
5000" is written against.
What leaves the machine
{
"tool": "mcp__razorpay__refund_payment", "action": "call", "destination": "razorpay",
"tool_use_id": "toolu_01AbC…",
"tool_input": { // the FULL argument JSON, as produced
"payment": {"transaction_amount": 6000, "currency": "INR"}
},
"signals": {},
"sdk_version": "2.0.0", "contract_version": "v3"
}
No SDK-side redaction, bucketing, or type-only reduction — that governance moved to
the backend (Ingest::ToolInput): it bounds an oversized payload, redacts a
credential-shaped value or a value under a secret-named key (api_key, password,
token, …) in place, and derives the field.<path> facts a policy can match on. A
credential passed as an ordinary tool argument (e.g. a curl command with an
Authorization header, or an MCP tool whose input includes an API key) is redacted
there, not on the SDK side — the SDK does no content scanning at all.
Architecture
tool call ──► capture()/check() ──► classify (action/destination) ──► bound (size only) ──► backend
structural parsers only src/actrail/bound.py /spans · /check
- Deterministic outside, fail-open at
/check, fail-safe at ingest. - The SDK does no content scanning — no secret/PII detection, no taint tracking, no
file/script provenance. It classifies a call's
actionanddestinationfrom the tool name (and, forBash, the command text) and boundstool_inputfor size; everything else is the backend's job.
After upgrading, run:
actrail init --key ak_live_... # idempotently upgrades owned hook matchers
actrail restart # loads the new SDK into the warm daemon
actrail doctor
Security & privacy
See SECURITY.md for the full picture. Short version: the SDK sends the
full tool_input — bounded for size, nothing more — and the backend is the boundary
that bounds, redacts, and validates it before anything is persisted or evaluated.
Development
uv venv && uv pip install -e ".[dev]"
uv run pytest # tests
uv run ruff check . # lint
uv run mypy # strict types
License
Metadata
Release files for actrail 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| actrail-2.0.0.tar.gz | 2.3 MB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| actrail-2.0.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.17+ x86-64, Linux glibc 2.5+ x86-64 | Details |
| actrail-2.0.0-cp312-cp312-macosx_13_0_arm64.whl | CPython 3.12 | CPython 3.12 | macOS 13.0+ ARM64 | Details |
| actrail-2.0.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.11 | CPython 3.11 | Linux glibc 2.5+ x86-64, Linux glibc 2.17+ x86-64 | Details |
| actrail-2.0.0-cp311-cp311-macosx_13_0_arm64.whl | CPython 3.11 | CPython 3.11 | macOS 13.0+ ARM64 | Details |
Total release size: 12.6 MB
Release files / actrail-2.0.0.tar.gz
| Download URL | actrail-2.0.0.tar.gz |
|---|---|
| Size | 2.3 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
999ddbf1d072ef4d5c189f60e0d59bde32bc6820845175f38e1a5a67a8887cb1
|
|
BLAKE2b-256 checksum How to use checksums |
d52f77ca782364a119b66e91af4cf21ce17a44569ff5bc69e2255ca708acee32
|
| 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 Sep 23, 2026.
Transparency logRelease files / actrail-2.0.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | actrail-2.0.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 2.3 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
c1f19bc3f8e56b74b169ad3592f82624a49d8d70afbba604e543eed1996adbe0
|
|
BLAKE2b-256 checksum How to use checksums |
459039e74baee3f7ea9c38790b83a426117f205ea6c53b0ddb300331b5a4e59f
|
| 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 Sep 23, 2026.
Transparency logRelease files / actrail-2.0.0-cp312-cp312-macosx_13_0_arm64.whl
| Download URL | actrail-2.0.0-cp312-cp312-macosx_13_0_arm64.whl |
|---|---|
| Size | 2.8 MB |
| Tags | CPython 3.12 macOS 13.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
a9a17e49e3c7d92ce463b7bc9032ec283e288fd6df20850577b90a9fb9e10b37
|
|
BLAKE2b-256 checksum How to use checksums |
5b7e435ebcfad5a015cb5cbfa5c3ab947af674b4d12542971e6cf14bb8883632
|
| 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 Sep 23, 2026.
Transparency logRelease files / actrail-2.0.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | actrail-2.0.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 2.3 MB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 Linux glibc 2.5+ x86-64 |
|
SHA-256 checksum How to use checksums |
ab10a4c7e0a3aa360e5bf635892abf8ee9619411f290b1a7ccde0b1376fac0dd
|
|
BLAKE2b-256 checksum How to use checksums |
b0b797fdac53aa15654498441b4292af67f943968bc4abd82835b867d7ca783c
|
| 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 Sep 23, 2026.
Transparency logRelease files / actrail-2.0.0-cp311-cp311-macosx_13_0_arm64.whl
| Download URL | actrail-2.0.0-cp311-cp311-macosx_13_0_arm64.whl |
|---|---|
| Size | 2.8 MB |
| Tags | CPython 3.11 macOS 13.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
f0b89ed0db741e3e50182a8f46bc6e67eb289d74ad2b0af25c141df5acc4a8aa
|
|
BLAKE2b-256 checksum How to use checksums |
8c3040242c850062670f979f0839941e6241d0cde82391bc8441af3adca6af86
|
| 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 Sep 23, 2026.
Transparency log