Skip to main content

hitl-guardrail 🛡️

A human-in-the-loop policy guardrail for LLM / AI-agent actions.

PyPI Python 3.9+ Zero dependencies MIT

When an AI agent can take consequential actions — send money, email a customer, delete a record, post publicly — you don't want a language model to be the last thing standing between intent and impact. hitl-guardrail wraps any such action in a small, deterministic policy layer that decides:

✅ approve automatically · 🧑‍⚖️ escalate to a human · ⛔ reject — each with an auditable reason and a 0–100 risk score.

  • 🔒 The model advises; policy decides. Rules live in tested code, not prompts, so behaviour is reproducible and can't drift with a model update.
  • 🧩 Framework-agnostic. Works with CrewAI, LangGraph, the OpenAI Agents SDK, or plain Python.
  • 🪶 Zero dependencies, fully typed, tiny.

Install

pip install hitl-guardrail

Quickstart

from hitl_guardrail import Guardrail, Rule, Decision

guard = Guardrail(
    rules=[
        Rule("amount_cap", lambda a: a["amount"] <= 2000,
             weight=40, message="amount over $2,000 needs a human"),
        Rule("receipt", lambda a: a.get("has_receipt", False),
             when=lambda a: a["amount"] > 50,           # only checked over $50
             message="receipt required for amounts over $50"),
        Rule("no_fraud", lambda a: not a.get("flagged_fraud", False),
             on_fail=Decision.REJECTED, weight=100, message="flagged as fraud"),
    ],
    auto_approve=lambda a: a["amount"] <= 200,           # small + compliant → auto
)

result = guard.evaluate({"amount": 2500, "has_receipt": True})
print(result.decision)     # Decision.NEEDS_HUMAN_REVIEW
print(result.risk_score)   # 40
print(result.reasons)      # ['amount over $2,000 needs a human']

Gate an action with the @protect decorator

The function runs only if the action is approved; otherwise your review/reject handlers take over.

review_queue = []

@guard.protect(on_review=lambda action, res: review_queue.append((action, res)))
def pay_expense(action):
    return charge_card(action)          # only runs when APPROVED

pay_expense({"amount": 5000})           # -> escalated, not charged

Without an on_reject handler a rejected action raises GuardrailError; without an on_review handler a review returns the GuardrailResult so you can route it yourself.

How the decision is made

  1. Every applicable rule runs. A rule returns True when the action complies.
  2. A failing rule adds its weight to the risk score and records a reason.
  3. Precedence: any on_fail=REJECTED failure → REJECTED. Otherwise any failed review rule, or risk_score >= risk_threshold (default 60) → NEEDS_HUMAN_REVIEW. Otherwise auto_approve(action) decides (defaults to approve).
  4. A rule that raises is treated as a failure and fails safe to human review.

Use with an agent framework

# CrewAI / LangGraph / OpenAI Agents SDK — same idea: guard the *tool*, not the prompt.
@guard.protect(on_review=queue_for_human, on_reject=notify_and_drop)
def transfer_funds(action: dict):
    banking_api.transfer(**action)

Why this exists

Extracted from a production multi-agent finance system (agentic-finance-crew), where the same principle applies: an LLM can propose, but a deterministic guardrail authorizes.

Development

pip install -e ".[dev]"
pytest -q
python examples/expense_approval.py     # decision routing
python examples/approval_workflow.py    # human-in-the-loop review queue (approve/reject)

See examples/approval_workflow.py for a complete human-approval workflow — auto-approve, park-for-review, and reject — built entirely from the public API.

License

MIT © Furqan Ali

Download files

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

Source Distribution

hitl_guardrail-0.1.0.tar.gz (10.0 kB view details)

Uploaded Source

Built Distribution

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

hitl_guardrail-0.1.0-py3-none-any.whl (8.5 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for hitl_guardrail-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2091a1a7e88248bd4db80c8f01d450a7f51ae30c3bfa1f11858c70ca0fe1bcb5
MD5 a128ad895aff7ad077824aad65b34fe1
BLAKE2b-256 ac5b734c16f2441ebeaf94d0cde38fff4ebc55787296aea0ada683b42b1704a0

See more details on using hashes here.

File details

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

File metadata

  • Download URL: hitl_guardrail-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.16

File hashes

Hashes for hitl_guardrail-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 acf50806b71842a8988d82ecfac019f7836aa3ad135205f869ecc4929dc80ec6
MD5 7bf9719aa68118e3071c15d9d1cf273e
BLAKE2b-256 299d2d8f0db365d16f5c1ccc081acf6a59601ed9e9559efe758b6429ade4133f

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page