Skip to main content

Action Policy Engine for AI agents: policy-as-code for tool-calls — evaluate, enforce (block/warn/approve), and trace agent actions, with the same policy asserted in CI. Plus local guardrails and an offline judge. Pure-Python, zero dependencies.

Project description

amanai

Action Policy Engine for AI agents — policy-as-code for tool-calls. Pure-Python, zero dependencies.

Write one policy for risky agent actions. Amanai evaluates every tool-call against it before the tool runs, enforces the decision, and records a structured trace as evidence. The same policy file asserts in CI — what you test is what you enforce. Decisions are deterministic: no LLM decides whether a high-risk tool runs.

pip install amanai

Action Policy Engine

Five verbs: load a policy, evaluate an action, protect a tool, collect a trace, assert it in tests.

from amanai import set_policy, tool, ToolBlocked, ApprovalRequired, collect_trace

set_policy("amanai.policy.json")          # load + validate (raises PolicyError if bad)

@tool(name="billing.refund", capability="money_movement", risk="high")
def refund_payment(amount): ...

refund_payment(amount=500)                # ToolBlocked / ApprovalRequired per policy
trace = collect_trace()                   # canonical evidence: action + decision + status

A policy is a list of rules. A rule matches on tool and/or capability, with optional args and context predicates, and carries an action:

[
  { "id": "discount-cap", "tool": "apply_discount",
    "args": [{ "arg": "pct", "op": ">=", "value": 50 }],
    "action": "block", "reason": "discount of 50% or more is never allowed" },

  { "id": "refund-approval", "tool": "refund_payment",
    "args": [{ "arg": "amount", "op": ">", "value": 100 }],
    "action": "require_approval" },

  { "id": "external-email", "capability": "external_comms",
    "args": [{ "arg": "to", "op": "email_external", "value": ["acme.com"] }],
    "action": "block" }
]
  • Outcomes: allow · block · warn · require_approval.
  • Operators: >= > <= < == != · contains · regex · in / not_in · email_external · domain_in / domain_not_in.
  • Modes (per request, never global): enforce blocks before execution · shadow records what it would block but lets the call run · test evaluates with no side effects.
  • The legacy flat rule {tool, arg, op, value} still loads (it defaults to block). Rules without an id get a deterministic generated one.
from amanai import set_mode, set_context, evaluate, ActionRequest

set_mode("shadow")                                   # observe before enforcing
set_context(role="support", tenant="t1", environment="prod")  # authz context for rules
evaluate(ActionRequest("apply_discount", {"pct": 90}))        # -> PolicyDecision(outcome="block", ...)

Assert the same policy in CI

from amanai.testing import assert_blocked, assert_no_violations

def test_excessive_discount_is_blocked():
    set_policy("amanai.policy.json")
    assert_blocked(apply_discount, pct=90)

def test_attack_trace_is_clean():
    run_agent(attack_prompt)             # produces a trace
    assert_no_violations(collect_trace())  # replays actions against the active policy

amanai.testing also ships assert_requires_approval, using_mode, and replay (re-evaluate a recorded trace against a policy).

Runtime guardrails (input / output, supporting)

from amanai import guard_input, guard_output, GuardrailBlocked

try:
    msg = guard_input(user_msg)          # raises GuardrailBlocked on injection
except GuardrailBlocked:
    reply = "I can't help with that."
else:
    reply = guard_output(run_agent(msg)) # redacts emails, cards, secrets

Offline judge & MCP checks (supporting)

Score an agent's input / response / tool-calls against detectors (string match, tool assertions, MCP checks; LLM-as-judge when you pass a gateway). The tool_assertion detector reuses the engine's operators, so the test side can't drift from runtime — a contract test guarantees it.

Monitoring (optional — needs an Amanai server)

from amanai import Monitor, collect_trace

mon = Monitor("http://localhost:8000", PUBLIC_KEY, SECRET_KEY)
mon.log_trace(collect_trace(), user_id="u123")   # canonical events, PII redacted

API

  • Engine: load_policy set_policy get_policy evaluate Policy Rule ActionRequest PolicyDecision TraceEvent PendingAction PolicyError
  • Modes / context: set_mode get_mode set_context get_context clear_context
  • Protect / collect: tool collect_trace collect_tool_calls record_tool_call reset registered_tools uncovered_tools ToolBlocked ApprovalRequired
  • Test: amanai.testingassert_blocked assert_requires_approval assert_no_violations using_mode replay
  • Policy lifecycle: clear_tool_policy (deactivate the active policy)
  • Guardrails: guard_input guard_output redact_pii detect_injection detect_pii GuardResult GuardrailBlocked
  • Judge / monitor: judge Monitor

Apache-2.0. Zero runtime dependencies.

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

amanai-0.3.0.tar.gz (31.9 kB view details)

Uploaded Source

Built Distribution

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

amanai-0.3.0-py3-none-any.whl (42.2 kB view details)

Uploaded Python 3

File details

Details for the file amanai-0.3.0.tar.gz.

File metadata

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

File hashes

Hashes for amanai-0.3.0.tar.gz
Algorithm Hash digest
SHA256 b442e4df62ab92796603efe51dfe4d66e214f6a08dca80ae6cb6f0c2abede7a2
MD5 fef556e55cc3a328510ddfb9dfc96fb1
BLAKE2b-256 5e391984deac9d732e3aa0182b85ba00d6de31d94dc252bd16ebe74bdf2200ae

See more details on using hashes here.

Provenance

The following attestation bundles were made for amanai-0.3.0.tar.gz:

Publisher: release.yml on ajipurn/amanai

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

File details

Details for the file amanai-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: amanai-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 42.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for amanai-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b5472463d0a2080bcdd13c1e5b298a788fc0534980bf63ce11ed03976d77ff07
MD5 12c11cdc0b977bd2b27625583e4a7546
BLAKE2b-256 91b8f3b48f84c71664f4504b6ba184ad331a6d1cf830622a4ffb6db994a57786

See more details on using hashes here.

Provenance

The following attestation bundles were made for amanai-0.3.0-py3-none-any.whl:

Publisher: release.yml on ajipurn/amanai

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