Skip to main content

tool-call-warrant v0.1.0

Pre-execution guard layer for AI agent tool calls. Warrants are structured confirmations that pass through a rule engine before a tool is allowed to execute.

Python 3.11+ Node 18+ Zero deps Tests: 235 License: MIT


Why this exists

AI coding agents (Claude Code, Cursor, AGY, Gemini CLI) execute tool calls with zero pre-execution confirmation. When an agent decides to strace a production server, delete 50k files, DROP TABLE, or POST to a webhook, the human sees only the retrospective log. This is the core "rogue agent" failure mode that developers complain about in production.

tool-call-warrant is a zero-dependency, cross-runtime (Python + Node) plugin that intercepts tool calls before execution and returns a structured warrant verdict: ALLOW, DENY, MODIFY, or CONFIRM.

Install

Python

pip install -e .
warrant-check --help

Node

npm install -g .
warrant-check --help   # uses scripts/warrant-check.mjs via package.json `bin`

Zero runtime dependencies in both languages. dependencies = [] / "dependencies": {}.

Quickstart

As a CLI

# Simulate a destructive call — returns DENY (exit 1)
warrant-check check --tool bash --args '{"command":"rm -rf /app"}' --format json

# Simulate a safe call — returns ALLOW (exit 0)
warrant-check check --tool mcp__filesystem__ls --args '{"path":"/app/docs"}'

# Force ALLOW despite DENY (human override; logs to audit trail)
warrant-check check --tool bash --args '{"command":"rm -rf /app"}' --confirm

# Inspect audit log
warrant-check audit --since 2026-08-09T00:00:00Z --format json

As a library (Python)

import sys; sys.path.insert(0, "src")
from warrant_core import classify_risk, get_verdict

risk, matched = classify_risk("bash", {"command": "rm -rf /"})
# risk = "DESTROY"; matched = ["destroy:recursive delete"]

verdict = get_verdict(risk)  # "DENY"

As a library (Node)

import { classifyRisk, getVerdict } from 'tool-call-warrant';

const [risk, matched] = classifyRisk("bash", { command: "rm -rf /" });
// risk = "DESTROY"; matched = ["destroy:recursive delete"]

const verdict = getVerdict(risk); // "DENY"

Risk Classification

Risk Patterns Verdict Exit code
DESTROY rm -rf, DROP TABLE, TRUNCATE, kill -9, shutdown, mkfs DENY 1
EXFILTRATE Private IPs, curl | sh, eval(base64_decode(...)), ~/.env, DB dumps, printenv CONFIRM 2
EXECUTE bash -c, eval(, subprocess, child_process.spawn, gcc/go build/rustc/npm install, | sh CONFIRM 2
OBSERVE ps aux, SELECT *, chmod 777, ls -R /, cat ~/.ssh/id_rsa ALLOW 0
BENIGN ls, git status, cat README.md, find ., npm test ALLOW 0
UNKNOWN (no pattern matched) CONFIRM 2

Global blocks (always force DENY → DESTROY):

  • curl <anything> | sh
  • wget -O- | sh
  • eval(base64_decode(...))

CLI Subcommands

Subcommand Purpose Exit codes
check Evaluate a tool call against rules 0=ALLOW/MODIFY, 1=DENY, 2=CONFIRM
diff Show arg changes (proposed → allowed) 0=ok, 1=invalid input
audit Read historical warrant decisions 0=ok, 1=invalid input
parse Validate warrant JSON schema 0=valid, 1=invalid

check flags

Flag Effect
--tool NAME (required) Tool name
--args JSON Tool arguments as JSON object (default {})
--rules PATH Path to rules file (reserved for v0.2)
--format json|text Output format (default text)
--confirm Human override: force ALLOW
--reject Human override: force DENY
--modify Human override: emit MODIFY verdict
--dry-run Do not write audit log entry
--audit With --dry-run: still write audit log

Hook Integration (per-agent)

{
  "event": "pre_tool_call",
  "tool": "*",
  "handler": "warrant-check --tool ${TOOL_NAME} --args ${TOOL_ARGS} --format json",
  "on_allow": "proceed",
  "on_deny": "block_and_log",
  "on_confirm": "pause_and_notify"
}

See skills/tool-call-warrant/SKILL.md for per-framework integration notes.

Cited Evidence (Honest Pillar)

  1. HN Ask: How do you enforce permissions for AI agent tool calls in production? — 350+ points, multiple "how do I prevent rogue agents" threads
  2. HN signal: "AgentWard — After an AI agent deleted files, I built a runtime enforcer."
  3. HN signal: "Runtime security for AI agents (injection, tool abuse, data exfiltration)"
  4. GitHub Search: @twire/guard (Edge/Node only, 0.1.1) and @jc4649/pi-toolcall-guard (pi-specific, 0.1.0) — both narrow in scope, neither Python+Node cross-runtime
  5. npm + PyPI: tool-call-guard, tool-call-confirm, tool-interceptor — no cross-runtime distribution found

Named Competitors

Package Runtime Limit
@twire/guard Edge/Node only No Python, narrow scope
@jc4649/pi-toolcall-guard pi-agent only Framework-locked, no general plugin

Limitations / Non-Goals

  • Rule engine is synchronous, single-process. No distributed enforcement across hosts.
  • Rules file is plaintext. No schema validation beyond JSON syntax (custom rules loader is v0.2).
  • First-run UX requires manual --audit to inspect behavior before enabling auto-confirm.
  • Not an OS-level sandbox. Use seccomp, firejail, gVisor for kernel-level isolation.
  • Not an LLM-side guardrail. Does not filter agent output or detect prompt-injection.
  • Not a substitute for human review. Edge cases (compound operations, multi-step plans) need operator judgment.

Plugin Manifest

See plugin.json for the full agent-runtime plugin declaration (hooks, scripts, rules, skills). The manifest declares dependencies: [] per spec.

Architecture

tool-call-warrant/
├── plugin.json             # Agent-runtime manifest
├── pyproject.toml          # Python packaging (zero deps)
├── package.json            # Node packaging (zero deps)
├── src/
│   ├── warrant_core.py     # Python rule engine (zero deps)
│   ├── index.mjs           # Node rule engine mirror (zero deps)
│   └── index.d.ts          # TypeScript definitions
├── scripts/
│   ├── warrant_check.py     # Python CLI
│   ├── warrant-check.mjs   # Node CLI
│   └── pre-push-gate.sh    # Mechanical gate before push
├── rules/
│   └── tool-warrant-rules.md
├── skills/
│   └── tool-call-warrant/SKILL.md
├── tests/
│   ├── COVERAGE.md         # 50 enumerated acceptance criteria
│   ├── test_warrant.py     # 128 pytest tests
│   └── test_warrant.mjs    # 107 Node tests
├── README.md
├── LICENSE                 # MIT
├── CHANGELOG.md
└── QA_REPORT.md            # Self-review (build card)

Verification

pytest -q             # 128 passed
npm test              # 107 passed
warrant-check --help  # CLI works
node scripts/warrant-check.mjs --help

License

MIT — see LICENSE.

Changelog

See CHANGELOG.md.

Download files

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

Source Distribution

tool_call_warrant-0.1.0.tar.gz (19.5 kB view details)

Uploaded Source

Built Distribution

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

tool_call_warrant-0.1.0-py3-none-any.whl (5.8 kB view details)

Uploaded Python 3

File details

Details for the file tool_call_warrant-0.1.0.tar.gz.

File metadata

  • Download URL: tool_call_warrant-0.1.0.tar.gz
  • Upload date:
  • Size: 19.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for tool_call_warrant-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4bfb17008e8536c2b077025d85822f7963ce708f2ada7fde8e8e65107ab0a2e2
MD5 bda097d31eb827fb0f6196e7a14cab59
BLAKE2b-256 bd3ca25521925d5e8d8ad272b6204388b87e930036584979c29f23a6e17eff85

See more details on using hashes here.

File details

Details for the file tool_call_warrant-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for tool_call_warrant-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d90249906506fd1e8a193d8a2bb257661f53971f98fe0a32512d29fadacbeee2
MD5 ff297208a1f2844549acb1ebc3d83be8
BLAKE2b-256 ac2efa1002917c62be5e514f7e43def1d20b4db42f35e74ce065556d8c6f1e5b

See more details on using hashes here.

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