Repository navigation
Releases: sameerbhatt/portcullis
Release list
v0.1.0 — first release
First release.
A per-action autonomy policy layer for AI agents. Decide, for every tool call, whether an agent may act on its own — based on the action's reversibility and blast radius, not the model's capability.
pip install portcullisThe decision
The whole library is one function:
decide(reversibility, blast_radius) -> outcome
| Low blast radius | High blast radius | |
|---|---|---|
| Reversible | auto-execute | execute + audit |
| Irreversible | execute + audit | require approval |
Model capability is not an input. A smarter model does not move delete_production_table out of the "require approval" cell — which is what makes this governance rather than a guardrail.
What's in it
GovernanceEngine.guard()— routes any callable through the policyPolicy— explicit per-tool profiles, fail-closed for anything undeclaredApprovalHandler— CLI, auto, and callback implementationsAuditLog— append-only JSONL, records all four outcomes, not just the blocked onesportcullis.adapters.langgraph.govern_all()— wraps LangChain tools in place; an existing graph needs no other changes
Design
The core imports nothing — no LangChain, no LLM SDK, no dependencies at all. The governance model is unit-tested with no API key and no network, so it can be read and trusted on its own. Denials raise ActionDenied rather than returning a sentinel, so the agent framework sees a real, catchable failure.
Tested on Python 3.10–3.13. Ships py.typed.
Not in v0.1
LLM-assisted classification of reversibility and blast radius (you declare profiles yourself, on purpose), web/Slack approval handlers, multi-approver RBAC, and persistence beyond the JSONL audit file. These are intentional cuts — the interfaces are shaped so each is an addition, not a rewrite.
MIT licensed.