Current collected state Current
Observed since 20 Oct, 21:27 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Declarative action policies for AI agents — approve, deny, or escalate any tool call before execution
Declarative action policies for AI agents — approve, deny, or escalate any tool call before execution.
pip install agent-action-policy
pip install agent-action-policy[yaml] # for YAML policy files
from action_policy import PolicyEngine, Action
engine = PolicyEngine.from_dict({
"policies": [{
"name": "no-force-push",
"match": {"tool": "bash", "args_pattern": "git push --force"},
"action": "deny",
"reason": "Force push requires human approval",
}]
})
decision = engine.evaluate(tool="bash", args={"command": "git push --force origin main"})
print(decision.denied) # True
print(decision.reason) # "Force push requires human approval"
| Sandboxing (containers) | Policy (this library) | |
|---|---|---|
| Controls | Where code runs | What the agent can do |
| Granularity | Process-level | Per-tool-call |
| Configuration | Infrastructure | YAML/Python |
| Use with | Any runtime | Any agent framework |
Sandboxing and policies are complementary. Use both.
policies:
- name: no-destructive-git
match:
tool: bash
args_pattern: "git (push --force|reset --hard|branch -D)"
action: deny
reason: "Destructive git operations require human approval"
- name: escalate-system-files
match:
tool: "~(file_write|write_file)"
path_patterns:
- "/etc/*"
- "/usr/*"
action: escalate
reason: "System file modification needs confirmation"
- name: approve-reads
match:
tool: "~(read|search|grep)"
action: approve
priority: 10 # lower = higher priority
engine = PolicyEngine.from_template("safe_coding")
| Template | What it protects |
|---|---|
safe_coding | Blocks force-push, rm -rf, system file writes, credential access, hook skipping |
safe_browsing | Blocks internal URLs, file:// protocol, escalates downloads |
safe_database | Blocks DDL (DROP/TRUNCATE), escalates DELETE and WHERE-less UPDATE |
strict | Whitelist mode — only read operations allowed, everything else denied |
# From YAML file
engine = PolicyEngine.from_yaml("policies.yaml")
# From dict
engine = PolicyEngine.from_dict({"policies": [...]})
# From template
engine = PolicyEngine.from_template("safe_coding")
# Evaluate
decision = engine.evaluate(tool="bash", args={"command": "rm -rf /"})
decision.action # Action.DENY
decision.denied # True
decision.reason # "..."
decision.policy_name # "no-rm-rf"
# Fail-closed mode (deny by default)
engine = PolicyEngine.from_template("strict", default_action=Action.DENY)
# Decorator
@engine.guard
def execute_tool(tool: str, args: dict = None):
... # raises PolicyDenied or PolicyEscalated
| Pattern type | Syntax | Example |
|---|---|---|
| Exact match | tool_name | "bash" |
| Glob | *, ?, [...] | "file_*" |
| Regex | ~pattern | "~(bash|shell|exec)" |
| Args regex | any regex | "git\\s+push\\s+--force" |
| Path glob | glob or ~regex | "/etc/*", "~\\.env$" |
MIT
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.1 | 25 Mar 2026 | 1 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Public sponsor counts have not been collected. These signals belong to the repository owner.
github · 1 observations shown. Missing days are unknown.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-21 | 0 | 2026-10-21T18:53:19.7018404Z |
Observed since 20 Oct, 21:27 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:d746bf9fd7712b1a9005ab051691bd3d526ced747e713b807375a02a5560abc3