Skip to main content

A pre-execution approval gate for AI agents: preview the plan, see the risks, approve or reject before anything runs.

Project description

๐Ÿ›ก๏ธ PreCheck Guardian

A pre-execution approval gate for AI agents. Preview the full plan, see the risk of every step, then approve, reject, or edit โ€” before anything runs.

CI python license deps

PreCheck Guardian rendering an agent plan with per-step risk levels and an approve/reject/edit prompt

Autonomous agents act fast and don't ask. One rm -rf, one DROP TABLE, one force-push, and the damage is done. PreCheck Guardian inserts a human-in-the-loop checkpoint between planning and execution: it parses what the agent is about to do, flags the dangerous steps, and waits for a human to sign off.

Framework-agnostic. No dependency on any specific agent framework. It's one function call โ€” wire it into LangChain, a custom ReAct loop, or your own tool runner. Zero required dependencies; rich/questionary are optional niceties.


Why this exists

As agents get more autonomous, the gap between "here's what I'll do" and "...and it's already done" gets dangerous. Most "human-in-the-loop" options today force a bad trade-off:

Approach Sees the whole plan first? Per-step risk scoring? Audit trail? Drop-in?
Just let the agent run โŒ โŒ โŒ โ€”
A raw input("y/n?") per tool โŒ (one step at a time) โŒ โŒ manual
Framework-specific approval callback partial โŒ โŒ locked to one framework
PreCheck Guardian โœ… โœ… (75 rules) โœ… (JSON-Lines) โœ… one call, any framework

You get the full plan up front, the risky steps highlighted, a real approve / reject / edit decision, and a compliance-ready audit log โ€” in one call, with zero required dependencies.


See it in 10 seconds

pip install precheck-guardian
python -m approval_hook        # render a sample plan with risk levels
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Approval Required โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ Demo Plan        ๐ŸŸข 1  ๐ŸŸก 1  ๐Ÿ”ด 2  โ›” 2    โฑ 15s                     โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
  #  Risk      Action                                  Tool
  1  LOW       SELECT * FROM users WHERE status=...    sql_query
  3  HIGH      UPDATE accounts SET billed = 1 ...      generic_tool   โš  modifies rows
  4  CRITICAL  DROP TABLE users_staging                sql_query      โš  destroys data
  5  CRITICAL  rm -rf /tmp/build                       file_delete    โš  unrecoverable
  6  HIGH      git push --force origin release         git            โš  overwrites history

Use it in 3 lines

from approval_hook import ApprovalGuard

guard = ApprovalGuard()
if guard.is_approved(agent_plan_text):
    run(agent_plan_text)          # only runs after a human approves

is_approved parses the plan, scores each step, prints it, prompts the operator, and writes an audit-log entry โ€” all in one call.


What it does

Capability Description
๐Ÿงฉ Plan parsing Turns free-form agent output (numbered lists, bullets, Step 1:โ€ฆ) or structured tool calls into typed steps.
๐Ÿšฆ Risk scoring 75 rule-based detectors across destruction, privilege, system control, RCE/supply-chain, infra, secrets and network. Conservative by design โ€” when unsure, it scores higher.
๐Ÿ‘ค Human approval Interactive Approve / Reject / Edit โ€” inline prompt, or a full-screen Textual TUI (optional).
๐Ÿชœ Policy gates Auto-approve LOW risk, prompt on MEDIUM+, optionally hard-block CRITICAL. Safe default: refuse, don't auto-run, when there's no human (CI).
๐Ÿ” Plan diffing Compare a revised plan against the original โ€” unified diff + a clean per-step summary.
๐Ÿ“ Audit trail Every decision appended to a JSON-Lines log (plan snapshot, max risk, actor, reason) for compliance. Secrets are auto-redacted.
๐Ÿ”’ Secret redaction Params like password, api_key, token are masked everywhere they're shown or logged.

Install

Available now, straight from GitHub (zero core dependencies):

pip install "git+https://github.com/uninhibited-scholar/precheck-guardian"
# with optional extras (rich tables, questionary menus, Textual TUI):
pip install "precheck-guardian[all] @ git+https://github.com/uninhibited-scholar/precheck-guardian"

Once published to PyPI, this becomes simply:

pip install precheck-guardian
pip install "precheck-guardian[all]"

Or from a local clone (for development):

git clone https://github.com/uninhibited-scholar/precheck-guardian
cd precheck-guardian
pip install -e ".[dev]"

How it fits into an agent loop

agent plans  โ”€โ–ถ  PreCheck Guardian  โ”€โ–ถ  approved?  โ”€โ–ถ  execute tools
                  โ”‚  parse                  โ”‚  no
                  โ”‚  score risk             โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ  abort / replan
                  โ”‚  show to human
                  โ””โ”€ record decision

Structured tool calls

from approval_hook import ApprovalGuard, ApprovalConfig

guard = ApprovalGuard(ApprovalConfig(block_critical=True, actor="ci-bot"))

decision = guard.review([
    {"tool": "read_data",  "args": {"path": "/data/in.csv"}, "description": "load input"},
    {"tool": "file_delete","args": {"path": "/data/in.csv"}, "description": "rm -rf /data/in.csv"},
])

if decision.proceed:
    execute(...)

Native OpenAI / LangChain tool-call traces

Already have a raw tool-call trace from the model? Hand it over as-is โ€” the guard detects the shape and parses it (OpenAI arguments JSON strings included):

# an OpenAI chat-completion response, an assistant message, a message list,
# or a list of tool-call dicts โ€” all work:
guard.review(openai_response)
guard.review([{"type": "function",
               "function": {"name": "run_sql", "arguments": '{"statement": "DROP TABLE t"}'}}])

Tuning the policy

from approval_hook import ApprovalConfig, RiskLevel

ApprovalConfig(
    require_above=RiskLevel.LOW,    # prompt for MEDIUM and up (None = always prompt)
    block_critical=False,           # True = auto-reject CRITICAL, never even ask
    audit_path="approval_audit.jsonl",
    actor="alice",
    non_interactive_default=None,   # what to do with no TTY; None = safe REJECT
)

One-line decorators

Add a checkpoint without restructuring code:

from approval_hook import gate_plan, review_result, guard_callable

@gate_plan("plan")               # review the plan passed in; skip body if rejected
def execute(plan): ...

@review_result()                 # review what the function returns; raise if rejected
def make_plan() -> str: ...

# wrap a single dangerous tool โ€” every call is reviewed (works with LangChain Tool(func=...))
safe_delete = guard_callable(delete_file, tool_name="delete_file")

LangChain

Wrap any LangChain tool so every call is reviewed first โ€” a drop-in replacement that keeps the tool's name, description and argument schema:

from langchain_core.tools import tool
from approval_hook.integrations.langchain import guard_langchain_tool

@tool
def delete_path(path: str) -> str:
    """Delete a file or directory."""
    ...

safe_delete = guard_langchain_tool(delete_path)   # give the agent this instead
# safe_delete.invoke({"path": "rm -rf /data"}) -> shown for approval / blocked

Install the optional extra: pip install "precheck-guardian[langchain]" (Python 3.10+).

Full-screen TUI

Prefer a richer review screen? Swap in the Textual UI โ€” same guard, same audit log:

from approval_hook import ApprovalGuard
from approval_hook.ui.tui import TextualApprovalUI

guard = ApprovalGuard(ui=TextualApprovalUI())
guard.review(agent_plan)     # opens an interactive approval screen

The PreCheck Guardian Textual TUI showing a 5-step plan with per-step risk levels and Approve/Edit/Reject buttons

Install the optional extra: pip install "precheck-guardian[tui]" (Python 3.9+).

Custom risk rules

from approval_hook import RiskAnnotator, RiskLevel
from approval_hook.core.risk_annotator import _rule

annotator = RiskAnnotator()
annotator.add_rule(_rule("no_prod", r"\bprod\b", RiskLevel.CRITICAL,
                         "Touches production.", "Use staging instead."))
guard = ApprovalGuard(annotator=annotator)

Examples

python examples/basic_approval.py        # interactive approve/reject/edit
python examples/with_diff.py             # diff an edited plan vs. the original
python examples/langchain_style_hook.py  # wire into an agent loop
python examples/decorator_gate.py        # one-line decorator + per-tool gating
python examples/langchain_real.py        # gate a real LangChain tool (needs langchain-core)
python examples/agent_workflow.py         # end-to-end multi-step agent; destructive step blocked
python examples/tui_approval.py           # full-screen Textual approval UI (needs textual)

Testing

pytest          # 67 tests, <1s

Design notes & honest scope

  • Risk scoring is rule-based, not a sandbox. It's a strong heuristic safety net to surface obvious danger for a human โ€” it is not a guarantee that an unflagged step is safe. Keep the human in the loop for anything destructive.
  • The parser is best-effort. Unstructured text becomes a single step rather than being silently dropped. For exact fidelity, feed it structured tool calls.
  • Zero core dependencies on purpose โ€” easy to vendor, easy to trust.

Contributions of new risk rules, parser formats and framework adapters are welcome.

License

MIT โ€” see LICENSE.

Project details


Download files

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

Source Distribution

precheck_guardian-0.1.0.tar.gz (36.7 kB view details)

Uploaded Source

Built Distribution

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

precheck_guardian-0.1.0-py3-none-any.whl (34.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: precheck_guardian-0.1.0.tar.gz
  • Upload date:
  • Size: 36.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for precheck_guardian-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e057c7dbf55cccac361882ae686b0305e35054568ae0d3b083b9924d2918798a
MD5 9fcdea5730143ad2b1a1cfacd71a21a1
BLAKE2b-256 01c3f824dd37831543774066903c3af6cae6cb6f33bff1acabb84593b09c3f91

See more details on using hashes here.

Provenance

The following attestation bundles were made for precheck_guardian-0.1.0.tar.gz:

Publisher: release.yml on uninhibited-scholar/precheck-guardian

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for precheck_guardian-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 377b759ded6fc34f000d9bf227941b28cfc2699c8ed9fec77eb7929b404bb527
MD5 2f8696d6231f702cac8006e127ffd0e5
BLAKE2b-256 2514faa62d8b5e525066eae465638c721b7ee30a470fdc380b7e80bfc93eb7ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for precheck_guardian-0.1.0-py3-none-any.whl:

Publisher: release.yml on uninhibited-scholar/precheck-guardian

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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