Skip to main content

Mizara - programmable authorization layer for AI actions

Project description

mizara

CI PyPI Python License

Authorization layer for AI agents. Call authorize() before any consequential action. Sub-2ms evaluation, policy-as-data, cryptographic receipt on every decision.

Also available for TypeScript/Node.js: @mizara/sdk

Install

pip install mizara

Quickstart

Local policy file

from mizara import create_mizara_client

mizara = create_mizara_client(policy_path="./policy.json")

result = mizara.authorize(
    actor={"id": "agent_ops_v4", "type": "autonomous_agent"},
    action={"name": "delete_production_resource"},
    resource={"type": "cloud_resource", "id": "res_9c21",
              "attributes": {"environment": "production"}},
)

if result.status == "DENY":
    raise Exception(result.enforcement.user_facing_error)
# result.status                   -> 'ALLOW' | 'DENY' | 'REDACT' | 'RE_ROUTE'
# result.cryptographic_receipt.id -> 'rcpt_8f3c...'

Hosted API - sign up at mizara.ai/signup, skip the local file:

import os
from mizara import create_mizara_client

mizara = create_mizara_client(
    api_key=os.environ["MIZARA_API_KEY"],
    client_id="acme_corp",
)

result = mizara.authorize(
    actor={"id": "agent_1", "type": "autonomous_agent"},
    action={"name": "delete_production_resource"},
    resource={"type": "cloud_resource", "id": "res_1",
              "attributes": {"environment": "production"}},
)

Hosted mode evaluates locally against a policy snapshot that's refreshed in the background (every 10 seconds by default). A Mizara outage doesn't fail every authorize() call, it keeps using the last policy successfully fetched. Receipts are generated locally and flushed to the hosted API asynchronously. For zero-loss delivery across a process crash, pass receipt_log_path:

mizara = create_mizara_client(
    api_key=os.environ["MIZARA_API_KEY"],
    client_id="acme_corp",
    receipt_log_path="./mizara-receipts.log",
    on_sync_error=lambda err: print(f"[mizara] policy sync failing: {err}"),
)

Call mizara.close() before your process exits to stop the background sync thread (a no-op in local mode, safe to always call). Construction blocks briefly for the first policy sync to settle (bounded by a 10-second network timeout) since Python has no async equivalent to return immediately and resolve later.

Waiting on a RE_ROUTE decision - a RE_ROUTE result means the action is held pending human approval. In hosted mode, wait_for_approval blocks until it's approved, denied, or the timeout elapses:

result = mizara.authorize(...)

if result.status == "RE_ROUTE":
    outcome = mizara.wait_for_approval(result.cryptographic_receipt.id)
    # outcome: "APPROVED" | "DENIED" | "TIMEOUT"

Only available on the hosted client; local mode has no server to hold pending approval state. Defaults to polling every 3 seconds for up to 25 minutes.

Verifying receipts - every receipt is signed with Ed25519, an asymmetric algorithm. Verification only needs the public key, not a call back to Mizara or the signing secret:

from mizara import verify_receipt, get_public_key

public_key = get_public_key()  # or fetch from GET /api/v1/public-key in hosted mode
is_valid = verify_receipt(result.cryptographic_receipt, public_key)

Set MIZARA_SIGNING_PRIVATE_KEY (a base64-encoded 32-byte Ed25519 seed) so the same key persists across restarts. Without it, a fresh key is generated per process and receipts stop being verifiable once it exits.

Policy format

Plain JSON. No Rego, no Cedar syntax.

{
  "policy_id": "pol_infra_guard_v1",
  "client_id": "acme_corp",
  "rules": [
    {
      "id": "rule_block_prod_delete",
      "target_action": "delete_production_resource",
      "condition": "resource.attributes.environment == 'production'",
      "effect": "DENY",
      "fallback_effect": "ALLOW",
      "remediation_message": "Production deletion requires approval."
    }
  ]
}

Condition expressions support comparisons, boolean logic, arithmetic, and .contains():

resource.attributes.amount <= 50.00
context.jurisdiction == 'EU' && context.data_classification.contains('PII')
context.session_total + resource.attributes.amount <= 500

CLI

mizara validate policy.json   # checks structure and condition syntax
mizara test policy.json       # checks coverage against 6 common risk scenarios
mizara test policy.json --json

mizara test runs six single-call scenarios spanning infrastructure, external communication, and sensitive data through your actual policy and reports, per scenario, whether a rule you wrote explicitly catches it (PROTECTED), whether it's only blocked by the fail-closed default because nothing matched (DEFAULT-DENIED), or whether it would go through (FAIL). Exits non-zero if any scenario fails, so it drops into CI as-is.

Integrations

Framework Example
LangGraph (raw StateGraph) examples/langgraph/
LangChain (create_agent) examples/langchain-agent/
OpenAI Agents SDK examples/openai-agents/
Hosted API examples/hosted-api/

LangChain (create_agent)

pip install "mizara[langchain]"
from langchain.agents import create_agent
from mizara import create_mizara_client
from mizara.langchain import mizara_middleware

mizara = create_mizara_client(policy_path="./policy.json")

agent = create_agent(
    model="gpt-4o-mini",
    tools=[delete_resource],
    middleware=[mizara_middleware(mizara)],
)

mizara_middleware() runs as wrap_tool_call middleware - a policy decision happens before the tool executes, and a non-ALLOW result returns a rejection ToolMessage without ever calling the tool. For the lower-level raw StateGraph pattern (building the graph nodes yourself), see examples/langgraph/ instead.

OpenAI Agents SDK

pip install "mizara[openai]"
from agents import function_tool
from mizara import create_mizara_client
from mizara.openai_agents import mizara_guardrail

mizara = create_mizara_client(policy_path="./policy.json")

@function_tool(tool_input_guardrails=[mizara_guardrail(mizara)])
def delete_resource(resource_id: str) -> str:
    ...

mizara_guardrail() runs as a tool_input_guardrail - a policy decision happens before the tool executes, and a non-ALLOW result blocks the call. Unlike exposing authorize() as a separate tool the model has to remember to call, this can't be skipped by the model just not calling it.

Design choices

Fail closed. No matching rule returns DENY, not ALLOW.

Most restrictive wins. When more than one rule matches an action, the most restrictive triggered outcome wins - DENY > RE_ROUTE > REDACT > ALLOW - regardless of rule order.

Resilient by default, with one honest exception. Hosted mode evaluates locally against a synced policy, so a Mizara outage doesn't stop your agent. A rule that uses context.session_total is the one case that can't get this guarantee: cumulative tracking is inherently centralized state, so if the session store is unreachable, that specific request fails closed rather than silently trusting a stale total.

Policy as data. Rules live in a JSON file that non-engineers can edit without a deploy.

No Cedar or Rego. Conditions are plain boolean expressions. The engine compiles them safely without eval().

Receipt on every call. Even ALLOW decisions are signed and stored. The audit trail is part of the product, not an afterthought.

License

Apache-2.0

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

mizara-1.2.0.tar.gz (35.3 kB view details)

Uploaded Source

Built Distribution

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

mizara-1.2.0-py3-none-any.whl (31.6 kB view details)

Uploaded Python 3

File details

Details for the file mizara-1.2.0.tar.gz.

File metadata

  • Download URL: mizara-1.2.0.tar.gz
  • Upload date:
  • Size: 35.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.2

File hashes

Hashes for mizara-1.2.0.tar.gz
Algorithm Hash digest
SHA256 7bd8458a03461de6dae8a23efe6fa9d1ad5bf11f25392f032d261db6a738aaa7
MD5 5ec542a42566ad7d0fc8142605185317
BLAKE2b-256 fc9e88ec82a4cb9a05dc467db00bae271d0e8dad90ef4b566bfd6519f99a3ef4

See more details on using hashes here.

File details

Details for the file mizara-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: mizara-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 31.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.2

File hashes

Hashes for mizara-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 49f1e1323fcc8e2113a7d44133acee41408bd0f148952ce9013efb72869ee302
MD5 8903d57948de0a187282bbcd16123b33
BLAKE2b-256 5f88d6aa84818f0e3f3503de846570aeb3e0255311f7c9c486e6d707e2714445

See more details on using hashes here.

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