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.
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/questionaryare 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
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
Release history Release notifications | RSS feed
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 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e057c7dbf55cccac361882ae686b0305e35054568ae0d3b083b9924d2918798a
|
|
| MD5 |
9fcdea5730143ad2b1a1cfacd71a21a1
|
|
| BLAKE2b-256 |
01c3f824dd37831543774066903c3af6cae6cb6f33bff1acabb84593b09c3f91
|
Provenance
The following attestation bundles were made for precheck_guardian-0.1.0.tar.gz:
Publisher:
release.yml on uninhibited-scholar/precheck-guardian
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
precheck_guardian-0.1.0.tar.gz -
Subject digest:
e057c7dbf55cccac361882ae686b0305e35054568ae0d3b083b9924d2918798a - Sigstore transparency entry: 1848101349
- Sigstore integration time:
-
Permalink:
uninhibited-scholar/precheck-guardian@7228a17a1634b64c2ef5a611e74cb811d6d318c2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/uninhibited-scholar
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7228a17a1634b64c2ef5a611e74cb811d6d318c2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file precheck_guardian-0.1.0-py3-none-any.whl.
File metadata
- Download URL: precheck_guardian-0.1.0-py3-none-any.whl
- Upload date:
- Size: 34.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
377b759ded6fc34f000d9bf227941b28cfc2699c8ed9fec77eb7929b404bb527
|
|
| MD5 |
2f8696d6231f702cac8006e127ffd0e5
|
|
| BLAKE2b-256 |
2514faa62d8b5e525066eae465638c721b7ee30a470fdc380b7e80bfc93eb7ca
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
precheck_guardian-0.1.0-py3-none-any.whl -
Subject digest:
377b759ded6fc34f000d9bf227941b28cfc2699c8ed9fec77eb7929b404bb527 - Sigstore transparency entry: 1848101462
- Sigstore integration time:
-
Permalink:
uninhibited-scholar/precheck-guardian@7228a17a1634b64c2ef5a611e74cb811d6d318c2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/uninhibited-scholar
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7228a17a1634b64c2ef5a611e74cb811d6d318c2 -
Trigger Event:
push
-
Statement type: