REDMTZ Seatbelt — AI Agent Governance
"No agent crosses the gate without passing through the law."
New Here? Start Here.
pip install redmtz
redmtz seatbelt # 5-step quickstart guide: hook → policy → status → run
redmtz status # confirm governance is live before you launch any agent
Building with LangGraph or CrewAI? Skip straight to Option 1 below. redmtz seatbelt prints the CLI-hook quickstart guide; redmtz status is your dashboard: active policy, loaded role, hook state, ledger health in one shot.
What Is Seatbelt?
Seatbelt is a Python library that wraps your AI agent's execution functions and does three things before any action runs:
- Blocks destructive actions — DROP TABLE, rm -rf /, credential theft, SQL injection, and more
- Signs every decision with Ed25519 cryptography — tamper-evident proof the decision happened
- Chains every decision to the one before it — nothing can be deleted or modified without detection
The result: when a regulator asks "what did your AI agent do?" — you produce cryptographic proof, not a story.
The one-liner that matters:
Guardrails are self-reported compliance. Seatbelt is audited enforcement.
Quickstart — 5 Minutes
pip install redmtz
Option 1 — LangGraph or CrewAI (recommended) — fail-closed governance wrapper, new in v1.6.0:
pip install redmtz[langchain] # or: pip install redmtz[crewai]
from redmtz.integrations.langchain import seatbelt_wrap_tool_call, blocklist_policy_check
from langgraph.prebuilt import ToolNode
wrap = seatbelt_wrap_tool_call(blocklist_policy_check({"wire_transfer"}))
tool_node = ToolNode(tools, wrap_tool_call=wrap)
# A denied call never reaches the tool handler — confirmed on the wire against
# a real StateGraph/ToolNode and langchain.agents.create_agent().
from redmtz.integrations.crewai import install_seatbelt_hook, blocklist_policy_check
install_seatbelt_hook(blocklist_policy_check({"wire_transfer"}))
# Registers a before_tool_call hook — a denial genuinely prevents the tool
# from executing, confirmed against CrewAI's real dispatcher, not just the
# hook function in isolation.
Both wrappers fail closed if the audit ledger can't record a decision — the tool never runs on an unrecorded ALLOW, not just on an explicit BLOCK. Full usage, including the timeout/SeatbeltMiddleware/install_seatbelt_hook options, is documented in each module's own docstring: redmtz/integrations/langchain.py, redmtz/integrations/crewai.py.
Option 2 — Python decorator — for any Python agent, 3 lines:
from redmtz import govern, GovernanceBlocked
@govern(rules="destructive_actions", policy="safe_defaults")
def execute_sql(query: str):
db.execute(query)
# Safe — passes through, signed envelope logged
execute_sql("SELECT * FROM users WHERE id = 42")
# Dangerous — blocked before execution, signed proof created
try:
execute_sql("DROP TABLE users")
except GovernanceBlocked as e:
print(f"Blocked: {e.pattern.description}")
print(f"Proof ID: {e.envelope['event_id']}")
print(f"Fix: {e.remediation_hint}")
Option 3 — Claude Code CLI hooks — best-effort registration, documented limits (see Known Limitations):
# Step 1: Wire the hook
redmtz hook install claude-code
# Step 2: Set policy
export REDMTZ_HOOK_POLICY=safe_defaults
# Step 3: (Optional) Load a role template — limits agent to approved commands only
export REDMTZ_HOOK_WHITELIST=$(python3 -c "import redmtz, os; print(os.path.join(os.path.dirname(redmtz.__file__), 'whitelists', 'role_devops_senior.json'))")
# Step 4: Confirm governance is active
redmtz status
# Step 5: Launch your agent — every tool call is now governed
claude
Hook execution, once registered, is deterministic and cannot be skipped by agent reasoning. Hook registration itself lives in a user-writable settings file with no tamper protection today — see Known Limitations below before relying on this for an adversarial threat model.
Option 4 — MCP server (voluntary/cooperative — for MCP-compatible agents only):
redmtz serve
Then point your MCP client at it. → Full connection guide
Note: MCP governance is cooperative — the agent calls
govern_actionvoluntarily. For enforced governance, use Option 1 (LangGraph/CrewAI) or Option 3 (CLI hook install).
How Seatbelt Works
Think of Seatbelt as a bouncer with a law degree. Every action your AI agent tries to take passes through two checks before execution:
Layer 1 — Blocklist (immutable, always runs): A fixed set of hardcoded patterns that can never be overridden — DROP TABLE, rm -rf /, SQL injection, credential theft, privilege escalation, pipe-to-shell, network exfiltration, service manipulation, and more (20 patterns as of this release — see the table below). If the action matches — it's blocked. No exceptions.
Layer 2 — Whitelist (role-based, your rules):
Define exactly what your agent IS allowed to do. Everything outside that set is implicitly denied. A DevOps agent can kubectl get and terraform plan. It cannot terraform destroy — even if no blocklist pattern matches.
Action submitted
│
▼
Layer 1: Blocklist (20 immutable patterns)
│
├── MATCH → BLOCK (always, whitelist cannot override)
│
▼
Layer 2: Whitelist (role-based allow set)
│
├── MATCH → ALLOW
└── NO MATCH → BLOCK (implicit deny)
│
▼
Build signed RDM-019 envelope
UUID v7 · SHA-256 digest · hash chain · Ed25519 signature
│
▼
Write to audit ledger (before return — no crash gap)
│
▼
Return decision to agent
Key principle: The audit entry is written before the function executes. Every decision — allow or block — is on the record, and any tampering with a written entry is cryptographically detectable. (Completeness — no entries ever silently missing under any condition — is a separate guarantee this version does not yet make; see Known Limitations below.)
What Gets Blocked — 20 Core Patterns
All patterns are hardcoded regex. Zero LLM. Zero AI. Deterministic and auditable.
| Pattern ID | Risk | What It Catches |
|---|---|---|
BLOCK_DROP_TABLE |
CRITICAL | DROP TABLE users, DROP_TABLE, Drop-Table |
BLOCK_DROP_DATABASE |
CRITICAL | DROP DATABASE / DROP SCHEMA — destroys an entire database or schema |
BLOCK_TRUNCATE |
CRITICAL | TRUNCATE TABLE users, truncate logs |
BLOCK_DELETE_NO_WHERE |
CRITICAL | DELETE FROM users (no WHERE clause) |
BLOCK_UPDATE_NO_WHERE |
CRITICAL | UPDATE users SET ... (no WHERE clause) — silently corrupts every row |
BLOCK_SQL_INJECTION_OBVIOUS |
CRITICAL | ' OR '1'='1, '; DROP TABLE--, UNION SELECT NULL |
BLOCK_RM_RF_ROOT |
CRITICAL | rm -rf /, rm -rf /etc, rm -rf /bin |
BLOCK_WILDCARD_RECURSIVE_DELETE |
CRITICAL | rm -rf /var/log/*, find . -delete |
BLOCK_DISK_WIPE |
CRITICAL | dd, mkfs, fdisk, parted targeting a block device |
BLOCK_DANGEROUS_FILE_WRITE |
CRITICAL | Writes or redirects to /etc/passwd, /root/.ssh, block devices |
BLOCK_PYTHON_DESTRUCTIVE_FS |
CRITICAL | os.remove/shutil.rmtree-style destructive filesystem calls that bypass shell-level rm blocks |
BLOCK_SHUTDOWN_REBOOT |
CRITICAL | shutdown, reboot, halt, poweroff |
BLOCK_PRIVILEGE_ESCALATION |
CRITICAL | sudo, user/group management, setuid |
BLOCK_GOVERNANCE_SELF_MODIFY |
CRITICAL | An agent writing to its own governance files — whitelist directory, role JSONs, the pattern/policy engine itself |
BLOCK_PIPE_TO_SHELL |
CRITICAL | curl | bash, wget | sh — remote code execution via pipe-to-interpreter |
BLOCK_NETWORK_EXFIL |
CRITICAL | Network exfiltration, reverse shells, firewall tampering |
BLOCK_GIT_FORCE_PUSH |
CRITICAL | git push --force — rewrites remote history |
BLOCK_CRED_THEFT |
HIGH | api_key = 'sk-abc123...', hardcoded secrets |
BLOCK_SHELL_EXEC_DANGEROUS |
HIGH | eval(user_input), exec(cmd), bash -c |
BLOCK_SERVICE_MANIPULATION |
HIGH | systemctl, crontab modification, scheduled-task tampering |
Patterns are scoped to avoid matching benign lookalikes — DELETE FROM users WHERE id=123 passes. SELECT * FROM drop_temp passes. That said, false positives have happened and been fixed as found (see RDM-260 under What's New in v1.5.2, below) — matching on English words and unanchored filename substrings, not the SQL/shell patterns themselves. Fixed, not claimed to never occur.
Policy Templates
| Policy | Behavior | Use When |
|---|---|---|
safe_defaults |
Block CRITICAL + HIGH. Allow everything else. | Starting point for most agents |
read_only |
Block CRITICAL + HIGH + MEDIUM. Allow LOW only. | Reporting / analytics agents |
audit_mode |
Allow all. Log everything. No enforcement. | Integration testing, observability |
strict_prod |
Block all matched patterns + implicit deny on unmatched. | Zero-tolerance production |
strict_whitelist |
Two-layer defense. Blocklist floor + whitelist ALLOW set. | Role-based agent governance |
@govern(rules="destructive_actions", policy="strict_prod") # implicit deny
@govern(rules="destructive_actions", policy="audit_mode") # observe, don't block
Role-Based Whitelists
Define exactly what your agent is authorized to do. Ship the whitelist file with your agent. Version control it. Every decision records its hash — proving the authorization in effect at the time.
# Start with a role template
redmtz serve --policy strict_whitelist --whitelist role_devops_senior.json
Three role templates ship with Seatbelt:
| Template | Role | What It Allows |
|---|---|---|
role_devops_senior.json |
Senior DevOps Engineer | kubectl get/describe/top/logs, terraform plan/show/validate, aws describe/list, CloudWatch metrics, scoped SQL SELECT |
role_mlops_engineer.json |
MLOps Engineer | S3 read/write, SageMaker describe/list, CloudWatch, docker build/images, python scripts, git read |
role_junior_admin.json |
Junior Admin | Read-only: ls, grep, ps, top, df, ping, curl GET, kubectl get/logs, git status |
Decision matrix:
Blocklist HIT → BLOCK (always — immutable floor)
Blocklist MISS + WL HIT → ALLOW
Blocklist MISS + WL MISS → BLOCK (implicit deny)
The security guarantee:
The blocklist defines what's never allowed. The whitelist defines what's approved. Both run. Blocklist wins on conflict. You can't whitelist your way past DROP TABLE.
redmtz status — Live Governance Snapshot
Before you launch any agent, run redmtz status to confirm what's loaded. One command shows everything:
$ redmtz status
redmtz v1.7.0 — Seatbelt Status
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Policy safe_defaults
Whitelist role_devops_senior (Senior DevOps Engineer) [sha256:abc12345...]
Hooks installed (PreToolUse + PostToolUse)
Ledger CHAIN INTACT · 42 entries · last: 2026-06-17T14:22:01 ALLOW safe_defaults
What each line means:
| Field | What it shows |
|---|---|
Policy |
Active policy from REDMTZ_HOOK_POLICY env var (or safe_defaults if unset) |
Whitelist |
Role name, description, and SHA-256 fingerprint of the loaded role file |
Hooks |
Whether PreToolUse + PostToolUse hooks are wired in ~/.claude/settings.json |
Ledger |
Chain integrity, total entry count, and most recent decision |
If Hooks shows not installed, run redmtz hook install claude-code first.
MCP Server — 4 Tools
Start the server:
redmtz serve # safe_defaults
redmtz serve --policy strict_prod # implicit deny
redmtz serve --policy strict_whitelist --whitelist role_devops_senior.json
| Tool | Description |
|---|---|
govern_action |
Evaluate any action. Returns ALLOW/BLOCK with signed envelope hash. |
audit_trail |
Query recent decisions. Returns environment, policy, patterns, envelope hash per row. |
verify_chain |
Walk the full ledger. Verify every hash link. Prove tamper-evidence. |
export_audit_csv |
Export full ledger as Ed25519-signed CSV. Hand it to a CISO. |
govern_action response:
{
"decision": "BLOCK",
"reason": "BLOCK_DROP_TABLE",
"patterns_matched": ["BLOCK_DROP_TABLE"],
"envelope_hash": "a59ed133...",
"signature": "fxgmFMU/...",
"governance_mode": "deterministic",
"sig_alg": "sha256+ed25519",
"remediation": "[BLOCK_DROP_TABLE] Use a migration runner (Alembic, Flyway)..."
}
The Signed Envelope — Your Cryptographic Proof
Every decision produces one envelope. This is what you show auditors, regulators, and legal teams.
{
"event_id": "019d31c3-b92a-7150-9d27-a9f897c0deef",
"timestamp_utc": "2026-04-04T02:14:33.421+00:00",
"governance_mode": "deterministic",
"actor": {
"type": "application",
"identity": "myapp.database.execute_sql",
"credential_method": "decorator"
},
"input": {
"digest": "a3f5c8d2e1b7f9c4...",
"token_count": 3,
"classification": "unknown"
},
"gate_decisions": [{
"gate": "seatbelt",
"decision": "block",
"reason": "BLOCK_DROP_TABLE",
"patterns": ["BLOCK_DROP_TABLE"]
}],
"policy": {
"name": "safe_defaults",
"version": "1.0.0",
"whitelist_hash": "4f93ce7eff3f8106...",
"whitelist_role": "devops_senior"
},
"hash_chain": {
"previous_hash": "2edf56acc1fd16ca...",
"current_hash": "2405c42ff0d032c5..."
},
"signatures": [{
"signer": "myapp.database.execute_sql",
"signature": "fxgmFMU/I8n6l/x+Mcj2...",
"type": "self"
}]
}
input.digest— SHA-256 of the raw query. Raw SQL is never stored. GDPR-safe by design.hash_chain— Modify any envelope and the chain breaks. Mathematical tamper detection.signatures— Ed25519. Any auditor with your public key can verify every decision, forever.whitelist_hash— SHA-256 of the whitelist file active at decision time. Proves authorization.governance_mode: "deterministic"— Proves this decision was made by pure logic, not an AI model.
Schema v3 Audit Columns
Every row in the audit ledger includes:
| Column | Description |
|---|---|
sig_alg |
Signature algorithm (sha256+ed25519 today — labeled for PQC upgrade path) |
environment |
Deployment context (prod/staging/dev). Set via REDMTZ_ENVIRONMENT. |
agent_id |
Ledger index label, mirrors actor.identity at write time — "claude-code-hook" on the Claude Code hook path, module.function on the @govern decorator path. Not driven by REDMTZ_AGENT_ID, on either path — that variable does not touch this column. As of RDM-279 (DEC-028), REDMTZ_AGENT_ID (and agent_id=/attach_agent_id()) sets a separate signed-envelope field, actor.instance_id, on the @govern decorator path only — see Known Limitations and "Distinguishing agents that share a tool" below. Do not rely on this ledger column for attribution claims that need to survive verification; use actor.instance_id for that. |
policy |
Policy template active at decision time |
patterns_matched |
Pipe-separated list of matched pattern IDs |
envelope_hash |
Canonical signed envelope hash — single integrity proof |
remediation |
Remediation hint (BLOCKs only) |
CISO CSV Export
govern_action tool → export_audit_csv
Or from Python:
from redmtz import database
result = database.export_csv("/tmp/audit_export.csv")
print(result["csv_hash"]) # SHA-256 of the CSV content
print(result["signature"]) # Ed25519 signature — verify with your public key
The exported CSV is hashed and signed. Any auditor can verify the export was not tampered with after generation.
Key Management — Zero Config
On first run, Seatbelt auto-generates an Ed25519 keypair:
~/.redmtz/keys/
sudo_signing.key ← private key (mode 0600)
sudo_signing.pub ← public key (share with auditors)
Override locations:
export REDMTZ_SUDO_KEY_PATH=/path/to/sudo_signing.key
export REDMTZ_SUDO_PUBKEY_PATH=/path/to/sudo_signing.pub
export REDMTZ_DB_PATH=/path/to/redmtz_audit.db
export REDMTZ_ENVIRONMENT=prod
Verify Your Audit Trail
# From MCP client
verify_chain
# From Python
from redmtz import database
print(database.get_chain_status())
{
"chain_valid": true,
"total_entries": 42,
"last_hash": "2405c42ff0d032c5...",
"message": "CHAIN INTACT. All 42 entries verified."
}
Sub-Agent Tree Visibility — v1.5.0+ (Free Tier)
When an orchestrator spawns a child agent, every @govern envelope produced by the child automatically records which parent spawned it. No configuration required — the harness sets the context, Seatbelt records it.
In-process harness:
from redmtz import govern, attach_upstream
@govern(rules="destructive_actions", policy="safe_defaults")
def child_query(query: str):
db.execute(query)
# Root orchestrator marks itself before calling the child
with attach_upstream(actor_id="orchestrator-v1", event_hash=parent_envelope_hash):
child_query("SELECT * FROM events WHERE id = 42")
# ↑ Envelope contains actor.upstream.actor_id + actor.upstream.event_hash
Subprocess harness (CrewAI, LangGraph, any agent framework):
# Parent sets these before launching the subprocess
export SEATBELT_UPSTREAM_ACTOR_ID="orchestrator-v1"
export SEATBELT_UPSTREAM_EVENT_HASH="<parent envelope hash>"
What you see in the audit trail:
{
"actor": {
"type": "application",
"identity": "myapp.child_query",
"credential_method": "decorator",
"upstream": {
"actor_id": "orchestrator-v1",
"event_hash": "a59ed133..."
}
}
}
What this is: Observability — you can see which agent spawned which.
What this is not: Authorization. upstream is recorded metadata, not a permission grant. Intent mandate and delegation bounds are Cockpit-tier features.
Distinguishing agents that share a tool — actor.instance_id (RDM-279, DEC-028)
upstream answers "who spawned this actor." It doesn't answer "which of several agents sharing the same tool function did this" — that's a different, common shape (several LangGraph nodes, or several CrewAI agents, all calling the same governed tool wrapper), and actor.identity alone can't distinguish them since it's derived from the function, not the caller.
from redmtz.integrations.langchain import seatbelt_wrap_tool_call, blocklist_policy_check
# Build one wrapper per agent — each gets its own label
wrap_trader = seatbelt_wrap_tool_call(blocklist_policy_check(set()), agent_id="trader-1")
wrap_research = seatbelt_wrap_tool_call(blocklist_policy_check(set()), agent_id="researcher-1")
Same mechanism on the env var (REDMTZ_AGENT_ID, process-wide) and directly via attach_agent_id() (in-process, finer-grained than a whole wrapper instance) — see redmtz.provenance.
{
"actor": {
"type": "application",
"identity": "redmtz.integrations.langchain._log_tool_call_decision",
"instance_id": "trader-1"
}
}
What this is: signed, tamper-evident attribution under an operator-assigned identifier. Combined with upstream, two agents sharing a tool are now distinguishable, and a delegation tree renders with real per-node labels instead of collapsing to one.
What this is not: cryptographic proof of which agent acted. The signature proves this label wasn't altered after the record was written — it does not prove the label was honest when written, and REDMTZ does not authenticate a caller's right to claim any particular value. Real per-agent identity backed by hardware attestation (a key born in a TEE, never leaving the device) is a different, higher-tier primitive, reserved for Hatchery/Aviant/Cockpit by design. Unset by default — this requires an explicit agent_id, it does not happen automatically.
What's New in v1.7.0
A v1.6.1 was planned (docs and CLI strings only) but never released under that number — RDM-279 landed in the same window and changes the signed envelope schema, which isn't a patch-level change under any reading. Both ship together here instead.
| Change | What it means |
|---|---|
actor.instance_id (RDM-279, DEC-028) |
Operator-assigned attribution for agents sharing a governed function — see "Distinguishing agents that share a tool" above. Set via agent_id= on the LangGraph/CrewAI wrappers, REDMTZ_AGENT_ID, or attach_agent_id(). Unset by default, byte-identical to pre-1.7.0 behavior if you don't use it. |
redmtz.integrations.langchain BLOCK path (RDM-285) |
A policy BLOCK coinciding with a ledger write failure previously crashed the graph run with an uncaught exception instead of returning the usual clean, signed-deny message. Fixed — the tool was never at risk of executing either way, this only changes how gracefully that already-safe outcome is reported. |
| README corrections | The agent_id ledger column and the Claude Code hook-path Known Limitations bullet both incorrectly stated REDMTZ_AGENT_ID reaches or overrides that column — it never has, on either path. Corrected. |
What's New in v1.6.0
The first release with public LangGraph and CrewAI integrations — Option 1 in the Quickstart above. It also closes three ledger-integrity defects present in every prior version.
| Change | What it means |
|---|---|
redmtz.integrations.langchain |
Fail-closed governance wrapper for LangGraph's wrap_tool_call hook. A denied call genuinely never reaches the tool. Install: pip install redmtz[langchain] |
redmtz.integrations.crewai |
Fail-closed governance wrapper for CrewAI's before_tool_call hook. Install: pip install redmtz[crewai] |
LedgerUnavailableError |
New GovernanceBlocked subclass — an action that would have been allowed now denies instead of proceeding silently if the ledger write fails. Existing except GovernanceBlocked: handlers still catch it. |
| Ledger integrity, 3 defects closed | Fail-open on write failure, a chain fork under concurrent writes, and a rare fail-open in the chain-head lookup. Full detail: security advisory. |
| Known Limitations, actor identity | Reworded to state precisely what the @govern decorator path (LangGraph/CrewAI) actually provides versus the Claude Code hook path — see below. |
What's New in v1.5.2
Security patch release — no new public API surface.
| Fix | What changed |
|---|---|
| Signing soft-fail (SB-014) | CanonicalEnvelope.build() previously caught a signing failure and silently persisted an empty signature with an error field, returning as if nothing went wrong. Now raises SigningFailedError; the PreToolUse hook catches it, logs loudly, and denies the action fail-closed rather than allowing an unrecorded decision through. |
Unbounded mcp dependency (SB-015) |
mcp>=1.0.0 had no upper bound and could resolve to mcp==2.0.0, which restructured its internal layout and broke redmtz serve with a ModuleNotFoundError. Pinned to mcp>=1.0.0,<2.0.0. |
| Two blocklist false positives (RDM-260) | BLOCK_GOVERNANCE_SELF_MODIFY matched bare filenames as an unanchored substring — a file merely ending in e.g. hooks.py anywhere on disk could trip it. BLOCK_SERVICE_MANIPULATION matched the bare word "at" in ordinary English. Both tightened; 19 new regression tests. |
What's New in v1.5.1
| Feature | What changed |
|---|---|
redmtz status |
New command — active policy, loaded role, hook state, and ledger health in one shot |
redmtz seatbelt |
Rewritten as a 5-step quickstart: hooks first, MCP moved to bottom and labeled voluntary |
v1.5.0 added swarm telemetry (sub-agent tree visibility) — free tier, Apache 2.0.
Only the latest release receives security patches — see SECURITY.md.
Test Suite — 212/212 Passing
Covers the decorator path, pattern library, provenance/sub-agent tree wiring, hash-chain and signature verification, concurrent-write fork prevention, and the LangGraph/CrewAI integrations. 13 test files — run the suite for the current per-file breakdown rather than trust a table here, which has gone stale before:
source .venv/bin/activate
pytest -q # 212/212
Compliance Mapping
OWASP LLM Top 10
| Category | Seatbelt Response |
|---|---|
| LLM01: Prompt Injection | All inputs validated against destructive patterns before execution |
| LLM02: Insecure Output Handling | LLM outputs treated as untrusted until governed |
| LLM05: Supply Chain | Hash-pinned lockfile, SHA-pinned GitHub Actions, pip-audit on every push, CycloneDX SBOM |
| LLM06: Sensitive Info Disclosure | Digest-only policy — raw inputs never stored in audit ledger |
| LLM08: Excessive Agency | 20 hardcoded patterns + role-based whitelist limit agent blast radius |
| LLM09: Overreliance | GovernanceBlocked forces visible failure; implicit deny stops unrecognized actions |
NIST AI Risk Management Framework
| Function | Seatbelt Component |
|---|---|
| GOVERN | Policy templates, role-based whitelists, implicit deny |
| MAP | ActionGrammar — 12 verbs × 8 domains × risk matrix |
| MEASURE | risk_level in envelope, pattern match counts, sig_alg, environment |
| MANAGE | GovernanceBlocked + remediation hints = active risk management |
Financial Services Recordkeeping — SEC Rule 17a-4 / FINRA Rule 4511
If you're building an agent that a broker-dealer or investment adviser will deploy, these are the rules that bind that deployment today, not in a future compliance window. SEC Rule 17a-4 requires broker-dealers to preserve records in a non-erasable, non-rewriteable format for a specified retention period, readily accessible for examination. FINRA Rule 4511 requires member firms to make and preserve books and records consistent with 17a-4.
Precisely what Seatbelt provides toward this, and what it doesn't: every governed decision is written to a SHA-256 hash-chained, Ed25519-signed ledger — any modification to a written entry is cryptographically detectable, and redmtz verify proves it. That's tamper-evidence: an alteration is detectable after the fact. It is not the same guarantee as WORM (write-once-read-many) storage media, which prevents alteration at the storage-hardware level regardless of whether anyone ever checks. Seatbelt doesn't claim to be a 17a-4 books-and-records custody system on its own — it's the audit trail your compliance stack sits on top of. Pair the ledger with WORM-compliant storage (object lock on the backing store, e.g.) for the storage-medium half of the requirement.
EU AI Act
Seatbelt's signed envelope directly addresses Article 12 (record-keeping and logging) for high-risk AI systems — automatic recording of events, tamper-evident chain, Ed25519 signatures, independently verifiable by any auditor. High-risk system obligations under the Act don't bind until December 2027; the recordkeeping shape Article 12 requires is the same one Seatbelt already produces today, well ahead of that date.
Supply Chain Security
| Control | Status | Detail |
|---|---|---|
| pip-audit on every push | ✅ | .github/workflows/security-audit.yml |
| Hash-pinned lockfile | ✅ | requirements.lock via uv pip compile --generate-hashes |
| GitHub Actions SHA-pinned | ✅ | Immutable commit SHAs, not mutable version tags |
| Secret masking in CI | ✅ | All keys masked before any log step |
| CycloneDX SBOM | ✅ | redmtz-<version>.sbom.json ships with every release |
| 24-hour rule | Policy | Never install zero-day releases without community stress-testing |
Known Limitations
Precision here matters more for a security product than for most software — an unexamined claim in this space is a gap wearing a disguise. Three boundaries this version has, stated plainly rather than discovered by a researcher:
Hook registration depends on file integrity we don't yet protect (RDM-280). Hook enforcement is deterministic and non-bypassable by agent reasoning — there is no API for an agent to skip an already-registered hook's execution, and no model participates in the allow/deny decision. But the registration itself lives in ~/.claude/settings.json, a user-writable file with no tamper protection today. An agent with file-write access to its own home directory could remove its own hook entry. Nothing shipped regressed to create this — the mechanism has always worked this way — and there is no patch that fully closes it: this is a scoping boundary, not a vulnerability introduced by a change. A layered detection fix (session-start and per-call integrity checks, fail-closed on detection) has a design on record but is not active engineering work right now — REDMTZ's product focus is the LangGraph and CrewAI integrations, where this specific gap does not exist. Treat this as a documented boundary of the Claude Code CLI path, not a fix in progress. Out-of-process enforcement (Cockpit) removes this dependency entirely, by design, since the agent never has file-level access to the enforcement boundary in that architecture.
Actor identity does not distinguish agents sharing the same code path by default — an explicit opt-in closes this on the decorator path (RDM-279, DEC-028). This looks different depending on which surface governs the call, and precision matters here — overselling either one wastes a real difference between them.
- Claude Code CLI hook path (
hooks.py): unchanged, still a real limitation.actor.identitydoes not yet vary per session, user, or machine — every Claude Code install currently produces the same actor label for every hook-originated decision.REDMTZ_AGENT_IDis not read anywhere on this path — it has no effect on this surface, signed envelope or ledger index column alike. No attribution between installs is possible on this path today. @governdecorator path (LangGraph, CrewAI, and any direct decorator use):actor.identityis still derived from the governed function itself — two different functions get two different, correctly distinct identities, unchanged. The real collision — two agents sharing one governed function producing an identical, indistinguishable label — is now closeable: a newactor.instance_idfield carries an operator-assigned identifier, set viaagent_id=on the LangGraph/CrewAI integration wrappers, theREDMTZ_AGENT_IDenv var, orattach_agent_id()directly for finer-grained control. This is signed, tamper-evident attribution under an operator-assigned identifier — not cryptographic proof of which agent acted. The signature proves the label wasn't altered after the envelope was written; it does not prove the label was honest when written, and REDMTZ does not authenticate the caller's right to claim any particular value. Real per-agent identity backed by hardware attestation (a key born in a TEE, never leaving hardware) is a different, higher-tier primitive — Hatchery/Aviant/Cockpit, not this field. Unset by default: if you don't assignagent_id, behavior is identical to before this field existed.
Do not rely on actor.identity alone to attribute a decision to a specific agent instance on either path. On the decorator path, set agent_id explicitly if per-agent attribution matters to you — it is not automatic. The hook path has no equivalent yet.
redmtz verify confirms tamper, not completeness (SB-013). A clean verification means no recorded entry has been altered. It does not yet guarantee no entry is missing — under specific write-contention conditions, an entry can fail to be written at all, which is a gap, not tampering, and the two are cryptographically distinguishable but not yet distinguished in the tool's own output. Root cause understood, fix scoped, not yet shipped.
None of these are secret from us — they're tracked, they're prioritized, and they're the reason Cockpit's architecture exists in the form it does. A limitations section is not a hedge; it's what lets every other claim in this document be trusted at face value.
What's Coming
Commercial tiers with centralized multi-agent fleet governance, human-in-the-loop approval workflows, and enterprise-grade audit retention are in active development.
Same envelope schema at every tier. Your Seatbelt audit history carries forward. You add capabilities — you replace nothing.
Patent Status
Provisional Patent Filed.
Claims include:
- Canonical signed event envelope with hash-chain integrity
- Ed25519 signing on AI governance decisions
- Role-based whitelist with signed hash in every envelope
governance_modefield enabling deterministic → neuro-symbolic upgrade path
Author
Robert Benitez — Founder & Sole Inventor REDMTZ — Comanche, TX
"AI agents should be provably safe, not just probably safe."
License
Apache License 2.0. Patent pending.
See LICENSE and NOTICE for full terms. The Apache 2.0 patent grant applies to REDMTZ Seatbelt only. Commercial tiers are offered under separate terms.
REDMTZ Seatbelt — Deterministic governance. Cryptographic proof. From line one.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 redmtz-1.7.0.tar.gz.
File metadata
- Download URL: redmtz-1.7.0.tar.gz
- Upload date:
- Size: 146.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a06f5d09207310be915988a48cef5b24ebe4fcf7c03330b0f280e94774aec1a0
|
|
| MD5 |
ff5b99ce54c4d8b01b2732af64b4603e
|
|
| BLAKE2b-256 |
5dcf73fbcf4d1d24e65b6ce471f05bca2b8c11d20faf257db84cb99969dcd9d6
|
File details
Details for the file redmtz-1.7.0-py3-none-any.whl.
File metadata
- Download URL: redmtz-1.7.0-py3-none-any.whl
- Upload date:
- Size: 103.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d53acf50f0fc6a56310fcfa6f523aabd3efbe94bb08b708852730f41827cf55a
|
|
| MD5 |
7f91b3a8f97ef40d48edb8072ce88820
|
|
| BLAKE2b-256 |
0731ea3f436a84b9f25aa5c2d52b11967830d6cdc2e09ae9cf19a73fbeaeb456
|