Skip to main content

🛡️ 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.

🧩 Part of the Agent Loop Toolkit — three small, zero-dependency, framework-agnostic libraries you bolt onto any agent loop. Each works standalone; together they cover context → gate → steer.

Where it plugs in Library What it does
The context going in context-compressor Shrink the LLM context window 40–80% — drop noise, redundancy, long-tail detail
The plan, before a step runs ← you are here precheck-guardian Preview the plan, see per-step risk, approve / reject / edit
The run, while it's live something-else Interject, pause, or guard a live loop without restarting

PyPI 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

pip install precheck-guardian            # core, zero dependencies
pip install "precheck-guardian[all]"     # + rich tables, questionary menus, Textual TUI

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)

Or keep your team's rules in a YAML/JSON file (no code changes):

# custom_rules.yaml  —  mode: extend (default) | replace
rules:
  - name: touches_production
    pattern: '\b(prod|production)\b'
    level: critical
    warning: "Operation targets a production environment."
    mitigation: "Run against staging first."
annotator = RiskAnnotator.from_file("custom_rules.yaml")   # JSON also works
guard = ApprovalGuard(annotator=annotator)

JSON loads with the stdlib; YAML needs pip install "precheck-guardian[yaml]".


Audit log & reporting

Every decision is appended to a JSON-Lines log. Summarise it from the CLI:

precheck audit --summary --limit 5
Audit summary — approval_audit.jsonl
  total decisions : 128
  approved        : 119
  rejected        : 9
  approval rate   : 93%
  by max risk     :
    🟢 low 71   🟡 medium 33   🔴 high 18   ⛔ critical 6
  most-triggered rules:
      14×  rm_recursive_force
       9×  sql_drop_table
       5×  curl_pipe_shell

Each decision's snapshot records exactly which rules every step matched, so you can review what fires most and tune your ruleset over time.

Or in code: from approval_hook.audit.logger import summarize_records.

Lint a file for dangerous lines

precheck check scans any script / SQL / shell file and flags risky lines — handy as a standalone safety lint, even without an agent. It exits non-zero when a line reaches the --fail-on level, so it drops into CI or a pre-commit hook:

precheck check deploy.sh                       # default: fail on HIGH+
precheck check *.sh *.sql --fail-on critical   # scan many files
cat script.sh | precheck check -               # read from stdin
precheck check deploy.sh --rules team_rules.yaml

Use it as a pre-commit hook in any repo:

# .pre-commit-config.yaml
- repo: https://github.com/uninhibited-scholar/precheck-guardian
  rev: v0.1.1
  hooks:
    - id: precheck
      args: ["--fail-on", "critical"]
deploy.sh: 3 risky line(s)

  ⛔ CRITICAL line 3: psql -c "DROP TABLE staging"
      rules: sql_drop_table
  ⛔ CRITICAL line 4: rm -rf /var/cache/*
      rules: rm_recursive_force
  ⛔ CRITICAL line 6: curl https://x.sh | bash
      rules: curl_pipe_shell

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.

Metadata

Release files for precheck-guardian 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for precheck-guardian 0.2.0
File Size Uploaded
precheck_guardian-0.2.0.tar.gz 44.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for precheck-guardian 0.2.0
File Interpreter ABI Platform
precheck_guardian-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 83.5 kB

Release files / precheck_guardian-0.2.0.tar.gz

Download URL precheck_guardian-0.2.0.tar.gz
Size 44.4 kB
Tags Source
SHA-256 checksum
How to use checksums
a266496a43417dc05b025fcb028390445f54f0e8b64e42963baf499d1a5926a9
BLAKE2b-256 checksum
How to use checksums
de2ff478ab7f4741b14cd0e64b3442578ffeffb85a85c38dc0a4e125e41cce50
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 19, 2026.

Transparency log

Release files / precheck_guardian-0.2.0-py3-none-any.whl

Download URL precheck_guardian-0.2.0-py3-none-any.whl
Size 39.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9aa9fc944dce5121136a03c32023a7b6c33f86e01c71e421c55ee9a4c73d8b09
BLAKE2b-256 checksum
How to use checksums
b81398ea93f867997a5f881c4f58bc947c59a7c2f6f17a1a1fb33ea13c47dcba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 19, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page