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.1.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.1-py3-none-any.whl (42.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: amanai-0.3.1.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.1.tar.gz
Algorithm Hash digest
SHA256 1def662e01b258defdc6321ec619a476732506d8ee1a2251572ab6d6c8350eee
MD5 b6fae869d73c110745cb988b8e69b500
BLAKE2b-256 fd5c3cc0b113d2139ec5f0650edf8213d60f40e20f602001e44b32b21d9294e3

See more details on using hashes here.

Provenance

The following attestation bundles were made for amanai-0.3.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: amanai-0.3.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f7d212eaaeb7fff51e7397456ba61442a8bf5060d5f51559f8bfeeabcb46980a
MD5 2f1fe0c77ab415e2b9cc36fa021e8898
BLAKE2b-256 ebdeaa4ea782af47d9d5a1f3cd5a32c2dc9fd0439ca10187dc57413a3a3a0644

See more details on using hashes here.

Provenance

The following attestation bundles were made for amanai-0.3.1-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