Skip to main content

initguard

Embedded ABAC policy engine for AI agents.

PyPI Python License

Write authorization policies in YAML with CEL conditions, evaluate them in-process. No sidecar, no HTTP, no external service. Policies use when/unless clauses for readable rules and return structured Decision objects with human-readable reasons and advice.

Install

pip install initguard

Quick start

Create a policy file:

# policies/tool_policy.yaml
apiVersion: initguard/v1
kind: ResourcePolicy
resource: tool
rules:
  - actions: ["execute"]
    effect: allow
    roles: ["agent"]
    when: request.resource.attr.tool_type in ["http", "search"]

  - actions: ["execute"]
    effect: deny
    roles: ["agent"]
    when: request.resource.attr.tool_type == "shell"
    unless: request.principal.attr.tags.exists(t, t == "trusted")
    advice: "Shell tools require the 'trusted' tag."

Load and evaluate:

from initguard import PolicyEngine, Principal, load_policies

engine = PolicyEngine(load_policies("./policies"))

agent = Principal(
    id="agent:helper",
    roles=["agent"],
    attrs={"tags": ["basic"]},
)

decision = engine.check(agent, "tool", "execute", resource_attrs={"tool_type": "shell"})

print(decision.allowed)  # False
print(decision.reason)   # "denied by tool_policy.yaml:rules[1]"
print(decision.advice)   # "Shell tools require the 'trusted' tag."

Policy format

Three document kinds, all in YAML.

Schema (optional)

Lint your policies against known attribute names. Catches typos at load time.

apiVersion: initguard/v1
kind: Schema
principals:
  agent:
    attrs:
      team: string
      tags: list
resources:
  tool:
    attrs:
      tool_type: string
    actions: [execute]

DerivedRoles

Conditional role elevation using CEL. A definition matches when when is true and unless is false (or absent). Names must be globally unique.

apiVersion: initguard/v1
kind: DerivedRoles
name: agent_roles
definitions:
  - name: trusted_agent
    parentRoles: ["agent"]
    when: request.principal.attr.tags.exists(t, t == "trusted")

  - name: same_team
    parentRoles: ["agent"]
    when: request.principal.attr.team != ""
    unless: request.principal.attr.team != request.resource.attr.team

ResourcePolicy

Allow/deny rules for a resource kind. Deny always wins over allow. Every rule must declare at least one of roles or derivedRoles.

apiVersion: initguard/v1
kind: ResourcePolicy
resource: tool
importDerivedRoles: [agent_roles]
rules:
  - actions: ["execute"]
    effect: allow
    derivedRoles: ["trusted_agent"]

  - actions: ["execute"]
    effect: deny
    roles: ["agent"]
    when: request.resource.attr.tool_type in ["shell", "python"]
    unless: request.principal.attr.tags.exists(t, t == "trusted")
    advice: "Requires the 'trusted' tag."

Derived roles are scoped to imports -- a ResourcePolicy only sees roles from the sets it explicitly imports, preventing privilege leakage across policy domains.

API

load_policies(policy_dir) -> PolicySet

Load all *.yaml / *.yml files from a directory. Files are loaded in sorted order for deterministic precedence. All CEL expressions are compiled at load time. Raises PolicyLoadError on invalid YAML, bad CEL syntax, duplicate role names, or broken references.

PolicyEngine(policy_set)

engine = PolicyEngine(policy_set)

engine.check(principal, resource_kind, action, resource_id="*", resource_attrs=None) -> Decision

Evaluate policies and return a Decision. Also available as check_async for async contexts.

engine.info() -> EngineInfo

Returns loaded policy summary: resource kinds, derived role sets, policy/rule counts, schema presence.

Decision

Field Type Description
allowed bool Whether the action is permitted
reason str Human-readable explanation, always populated
matched_rule str Stable rule identifier, e.g. "tool_policy.yaml:rules[1]"
advice str From the rule's advice field, or empty

Principal

Field Type Description
id str Identity string, e.g. "agent:code-reviewer"
roles list[str] Role list, e.g. ["agent", "team:platform"]
attrs dict[str, Any] Attributes for CEL conditions

CEL expressions

Conditions use Google Common Expression Language. Supported patterns:

# List membership
request.resource.attr.tool_type in ["shell", "python"]

# Existential quantifier
request.principal.attr.tags.exists(t, t == "trusted")

# Attribute equality
request.principal.attr.team == request.resource.attr.team

# Boolean operators
!request.principal.attr.tags.exists(t, t == "admin") && request.resource.attr.tool_type == "shell"

Missing attributes in CEL expressions evaluate to false (condition not met), not an error.

Development

uv sync --all-extras
uv run pytest tests/ -v
uv run ruff check . && uv run ruff format --check .

License

MIT OR Apache-2.0

Release files for initguard 2026.3.3

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

Source distribution (sdist)

Source distribution for initguard 2026.3.3
File Size Uploaded
initguard-2026.3.3.tar.gz 62.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for initguard 2026.3.3
File Interpreter ABI Platform
initguard-2026.3.3-py3-none-any.whl Python 3 none any Details

Total release size: 78.7 kB

Release files / initguard-2026.3.3.tar.gz

Download URL initguard-2026.3.3.tar.gz
Size 62.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c117d010572e9acc3aa9fc632758c20466eb6bf914ee2171ab358e662a71013a
BLAKE2b-256 checksum
How to use checksums
8aec111fb385a7cde080f65696507c754350577a8f9b631b728b715d9d51fdc9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 Mar 29, 2026.

Transparency log

Release files / initguard-2026.3.3-py3-none-any.whl

Download URL initguard-2026.3.3-py3-none-any.whl
Size 16.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6942825e6d7e885108f073dcb7089976b0c959a0126787109a41cef7ec11bcd3
BLAKE2b-256 checksum
How to use checksums
1cbded0396e36d4a3883d0ba7233d0f66a7983e7322bf8ff22d35dc3a0e97372
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 Mar 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2026.3.3 This release

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