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 as metadata-only 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 (
refund > $500 without approval → require_approval) evaluated in< 50ms, fail-open. No model in the verdict. - Metadata-only by construction. The SDK never sends raw arguments or results. It emits a redacted, per-field skeleton — keys kept, values stripped or transformed — built from scratch, never copied.
- An always-on secrets floor. API keys, tokens, private keys, passwords, connection strings are never emitted, and it can't be turned off.
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.
Optional extras for deeper local scanning:
pip install "actrail[ner]" # + Presidio / spaCy for names & unstructured PII
pip install "actrail[full]" # + transformers
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_... # wires the hook, starts the daemon in shadow mode
actrail enforce on # arm PreToolUse enforcement when you're ready
actrail doctor # verify config · hooks · daemon
Any agent (the library)
import actrail
actrail.init(key="ak_live_...", agent="support-bot")
# Before a risky action — get a deterministic verdict (fail-open, < 50ms).
verdict = actrail.check(
trail_id="sess_42",
tool="pay.api",
action="refund",
payload={"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 metadata-only telemetry (fire-and-forget).
actrail.capture(
trail_id="sess_42",
tool="pay.api",
action="refund",
payload={"order": {"amount": 2500}, "customer": {"email": "alice@example.com"}},
)
payload is the structured tool-call args. Actrail walks it into a governed
fields[] envelope — it never leaves your machine as raw data.
The telemetry contract
Every field passes through a transform ladder, least → most revealing, and the customer governs it per field (default-deny):
| Rung | What's emitted | Example |
|---|---|---|
drop |
nothing (skeleton only) | unknown fields |
type_only |
just the type | customer.email → (type: email) |
derived |
a safe derivation | email → domain:example.com |
bucket |
a coarse bucket | amount: 2500 → 1000_10000 |
token |
a one-way HMAC pseudonym | join without revealing |
raw |
the value verbatim | only for non-secret, opted-in fields |
Three guarantees stack, in order:
- Default-deny — an un-contracted field gets a conservative per-type default.
- Secrets floor — a secret-typed field, or any value that looks secret, is
forced to
drop. Non-overridable — a contract can never lift a secret onto the wire. - Outbound validator (fail-closed) — every emitted value is re-scanned and scrubbed if it still looks secret, the last line before anything leaves.
A seeded fuzz test asserts the invariant under the
worst case — every field forced to raw: no secret ever appears in an emitted value.
What leaves the machine
{
"tool": "pay.api", "action": "refund", "destination": "internal",
"data_classes": ["financial", "pii"], // derived from the envelope
"fields": [ // the redacted skeleton
{"path": "order.amount", "semantic_type": "amount", "handling": "bucket", "value": "1000_10000"},
{"path": "customer.email", "semantic_type": "email", "handling": "type_only"},
{"path": "auth.api_key", "semantic_type": "api_key", "handling": "drop"} // floored — no value
],
"amount": 2500, // a first-class grammar fact
"taint_sources": [{"table": "prod.customers"}], // enables "data from prod.customers" policies
"taint": ["email:v1:9f3a…"], // one-way fingerprints (flow, not values)
"sdk_version": "1.0.0", "contract_version": "v1"
}
No args. No result. No raw values. Ever.
Architecture
tool call ──► capture()/check() ──► enrich (taint) ──► contract pipeline ──────► backend
payload · content HMAC fingerprints build ▸ govern ▸ validate /spans · /check
fields[] · amount · sources
- Deterministic outside, fail-open at
/check, fail-safe at ingest. - BYO scanner — the enrichment scanners implement a simple
Scannerprotocol. - Optional NER (
pip install actrail[ner]) for richer PII detection; the default path stays lightweight (regex + entropy +detect-secrets).
Security & privacy
The metadata-only guarantee is by construction, not detection — see SECURITY.md. Short version: raw payloads never leave the machine, secrets are floored non-overridably, taint is one-way HMAC, and the wire is fail-closed validated.
Development
uv venv && uv pip install -e ".[dev]"
uv run pytest # tests (+ safety-invariant fuzz)
uv run ruff check . # lint
uv run mypy # strict types
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file actrail-1.0.2.tar.gz.
File metadata
- Download URL: actrail-1.0.2.tar.gz
- Upload date:
- Size: 2.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27634b513d8f717ed348117636d549f2d9e15ecf324a2d6f01e3dd3f4e5cbc37
|
|
| MD5 |
fe750c1a238f04efc9b19cdd107b3f5e
|
|
| BLAKE2b-256 |
7e44ec132addc4f8dfd033cba53359f7252d0eccde69a1ef480bfcdb55d76d5d
|
Provenance
The following attestation bundles were made for actrail-1.0.2.tar.gz:
Publisher:
release.yml on actrailhq/actrail-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
actrail-1.0.2.tar.gz -
Subject digest:
27634b513d8f717ed348117636d549f2d9e15ecf324a2d6f01e3dd3f4e5cbc37 - Sigstore transparency entry: 2337397764
- Sigstore integration time:
-
Permalink:
actrailhq/actrail-sdk@abef75ea75c9ff32ad19da5d9d93d8624ebc6567 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/actrailhq
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@abef75ea75c9ff32ad19da5d9d93d8624ebc6567 -
Trigger Event:
push
-
Statement type:
File details
Details for the file actrail-1.0.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: actrail-1.0.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 2.3 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
490ea5034e1a8ef1b4ee33da6020a77d578a00c989c85c407aecddff3d007b2e
|
|
| MD5 |
e65a7d290fd6513c2cbf26701e8a5da8
|
|
| BLAKE2b-256 |
6fbe4fd06ba2ce257e501bd782d4a1b0b588110bdb89c01771c4f772d1bcbd5f
|
Provenance
The following attestation bundles were made for actrail-1.0.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on actrailhq/actrail-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
actrail-1.0.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
490ea5034e1a8ef1b4ee33da6020a77d578a00c989c85c407aecddff3d007b2e - Sigstore transparency entry: 2337397781
- Sigstore integration time:
-
Permalink:
actrailhq/actrail-sdk@abef75ea75c9ff32ad19da5d9d93d8624ebc6567 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/actrailhq
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@abef75ea75c9ff32ad19da5d9d93d8624ebc6567 -
Trigger Event:
push
-
Statement type:
File details
Details for the file actrail-1.0.2-cp312-cp312-macosx_12_0_arm64.whl.
File metadata
- Download URL: actrail-1.0.2-cp312-cp312-macosx_12_0_arm64.whl
- Upload date:
- Size: 2.3 MB
- Tags: CPython 3.12, macOS 12.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0038aab6ab63e0da6ab028027fe8ea42dbdca13f806f7d848095776fbebf848f
|
|
| MD5 |
d020612a34d95adfd60d7bee448a08ff
|
|
| BLAKE2b-256 |
6af3a574520e75c01a685ada56e7bdf37059fa59cd9c97c20a89d697a623fd01
|
Provenance
The following attestation bundles were made for actrail-1.0.2-cp312-cp312-macosx_12_0_arm64.whl:
Publisher:
release.yml on actrailhq/actrail-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
actrail-1.0.2-cp312-cp312-macosx_12_0_arm64.whl -
Subject digest:
0038aab6ab63e0da6ab028027fe8ea42dbdca13f806f7d848095776fbebf848f - Sigstore transparency entry: 2337397803
- Sigstore integration time:
-
Permalink:
actrailhq/actrail-sdk@abef75ea75c9ff32ad19da5d9d93d8624ebc6567 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/actrailhq
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@abef75ea75c9ff32ad19da5d9d93d8624ebc6567 -
Trigger Event:
push
-
Statement type:
File details
Details for the file actrail-1.0.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: actrail-1.0.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 2.3 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb158c4231407f291600a7d2b15efe2d64b969418509ca2bc39f9c0021cae054
|
|
| MD5 |
46ca2120bd18396d1c2e89339441a5d5
|
|
| BLAKE2b-256 |
b01611073fd45162067bc8f9a8292ca1b670a3951aa33807b83970ac33bc4447
|
Provenance
The following attestation bundles were made for actrail-1.0.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on actrailhq/actrail-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
actrail-1.0.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
fb158c4231407f291600a7d2b15efe2d64b969418509ca2bc39f9c0021cae054 - Sigstore transparency entry: 2337397794
- Sigstore integration time:
-
Permalink:
actrailhq/actrail-sdk@abef75ea75c9ff32ad19da5d9d93d8624ebc6567 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/actrailhq
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@abef75ea75c9ff32ad19da5d9d93d8624ebc6567 -
Trigger Event:
push
-
Statement type:
File details
Details for the file actrail-1.0.2-cp311-cp311-macosx_12_0_arm64.whl.
File metadata
- Download URL: actrail-1.0.2-cp311-cp311-macosx_12_0_arm64.whl
- Upload date:
- Size: 2.3 MB
- Tags: CPython 3.11, macOS 12.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
80ee381a43d52577c1c92f5a63257a5e25fe458ccf9093a933010ae25475087f
|
|
| MD5 |
26f22dabc7cfde074fae491b3cbdf912
|
|
| BLAKE2b-256 |
42c5128912fdd28740f4041438320e271141bc82c7df1100a54b02c57fee4c62
|
Provenance
The following attestation bundles were made for actrail-1.0.2-cp311-cp311-macosx_12_0_arm64.whl:
Publisher:
release.yml on actrailhq/actrail-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
actrail-1.0.2-cp311-cp311-macosx_12_0_arm64.whl -
Subject digest:
80ee381a43d52577c1c92f5a63257a5e25fe458ccf9093a933010ae25475087f - Sigstore transparency entry: 2337397821
- Sigstore integration time:
-
Permalink:
actrailhq/actrail-sdk@abef75ea75c9ff32ad19da5d9d93d8624ebc6567 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/actrailhq
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@abef75ea75c9ff32ad19da5d9d93d8624ebc6567 -
Trigger Event:
push
-
Statement type: