Arden Python SDK
Complete reference for the ardenpy SDK — secure your AI agents with runtime policy enforcement.
Introduction
The Arden Python SDK provides runtime security for AI agents by enforcing policies on every tool call. This document covers every public function, class, parameter, return value, exception, and behavioral detail.
How Arden Works
Every tool call protected by Arden is evaluated against your configured policies before execution. The policy engine can allow, block, or require human approval for each action.
Installation
pip install ardenpyRequires Python 3.8 or later.
How It Works
Every tool call protected by Arden follows this sequence:
- Your code calls the wrapped function (e.g.
safe_refund(150.0, customer_id="cus_abc")). - The SDK sends the tool name and all arguments to the Arden policy engine.
- The policy engine evaluates the call against the rules you configured in the dashboard for this agent.
- One of three decisions is returned:
- allow — the SDK immediately executes the original function and returns its result.
- block — the SDK raises
PolicyDeniedErrorwithout executing the function. - requires_approval — a human must approve or deny the call on the Arden dashboard before anything executes.
Important: The original function is never executed unless the policy explicitly allows it or a human approves it.
Configuration
Configure the SDK once at application startup, before any calls to guard_tool().
configure()
ardenpy.configure(
api_key: str | None = None,
api_url: str | None = None,
environment: str | None = None,
timeout: float | None = None,
poll_interval: float | None = None,
max_poll_time: float | None = None,
retry_attempts: int | None = None,
) -> ArdenConfigSets the global SDK configuration. Returns the resulting ArdenConfig instance.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| api_key | str | ARDEN_API_KEY env var | Your agent's API key. Keys beginning with arden_test_ automatically set environment="test". |
| api_url | str | Auto-set from environment | Base URL for the Arden API. Override only if self-hosting. |
| environment | str | "live" | Either "test" or "live". Auto-detected from the API key prefix when possible. |
| timeout | float | 30.0 | Seconds before an individual HTTP request to the Arden API times out. |
| poll_interval | float | 2.0 | Seconds between status checks when polling for approval in wait or async modes. |
| max_poll_time | float | 300.0 | Maximum total seconds to wait for a human decision before raising ApprovalTimeoutError. |
| retry_attempts | int | 3 | Number of times to retry a failed HTTP request before raising ArdenError. |
Returns
ArdenConfig
Raises
Example
import ardenpy as arden
arden.configure(
api_key="arden_live_3e6159f645814adfa86b01f8c368d503",
timeout=60.0,
max_poll_time=600.0,
)Notes
- • configure() must be called before any guard_tool() call.
- • Calling configure() a second time overwrites the previous configuration globally.
- • The api_key can also be set via the ARDEN_API_KEY environment variable.
guard_tool()
ardenpy.guard_tool(
tool_name: str,
func: Callable,
approval_mode: str = "wait",
on_approval: Callable[[WebhookEvent], None] | None = None,
on_denial: Callable[[WebhookEvent], None] | None = None,
) -> CallableWraps func with Arden policy enforcement. Returns a new callable with the same signature as func. The original function is not modified.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| tool_name | str | — | The name used to look up this tool's policy in the dashboard. |
| func | Callable | — | The function to protect. Must be a plain Python callable. |
| approval_mode | str | "wait" | How the SDK behaves when a policy decision of requires_approval is returned. One of "wait", "async", or "webhook". |
| on_approval | Callable | None | Required when approval_mode is "async" or "webhook". Called when a human approves the action. |
| on_denial | Callable | None | Required when approval_mode is "async" or "webhook". Called when a human denies the action. |
Returns
A callable with the same signature as func.
Raises
Example
import ardenpy as arden
arden.configure(api_key="arden_live_...")
def issue_refund(amount: float, customer_id: str) -> dict:
# real implementation
return {"refund_id": "re_123", "amount": amount}
safe_refund = arden.guard_tool("stripe.issue_refund", issue_refund)
# Later, in your agent or request handler:
result = safe_refund(150.0, customer_id="cus_abc")Approval Modes
When a policy decision of requires_approval is returned, the SDK's behavior depends on the approval_mode you set on guard_tool().
Wait Mode
approval_mode="wait" # defaultBehavior: Blocks the calling thread. Polls the Arden API every poll_interval seconds until a human approves or denies the action on the dashboard, or until max_poll_time seconds have passed.
- If approved: executes func and returns its result.
- If denied: raises PolicyDeniedError.
- If max_poll_time is exceeded: raises ApprovalTimeoutError.
When to use: Scripts, CLI tools, synchronous web request handlers, or any context where blocking the current thread is acceptable.
Async Mode
approval_mode="async",
on_approval=...,
on_denial=...,Behavior: Returns a PendingApproval object immediately. A daemon background thread begins polling for the approval decision. When a human acts on the dashboard, the thread calls either on_approval or on_denial.
When to use: Long-running services (agents, workers) where you cannot block the main thread but also don't have an HTTP server to receive webhooks.
Webhook Mode
approval_mode="webhook",
on_approval=...,
on_denial=...,Behavior: Returns a PendingApproval object immediately. No background thread is started. Instead, when a human acts on the Arden dashboard, the Arden backend makes an HTTP POST to the webhook URL you configured for this agent in the dashboard.
When to use: Production services with a publicly reachable HTTP endpoint, or any scenario where you want push-based delivery without long-lived polling threads.
Exceptions
All exceptions inherit from ArdenError, which itself inherits from Exception.
ArdenError
class ArdenError(Exception): ...Base class for all Arden SDK exceptions. Catch this to handle any Arden-related error in one place.
PolicyDeniedError
class PolicyDeniedError(ArdenError):
tool_name: strRaised when a tool call is blocked, either automatically by policy (block decision) or because a human denied it on the dashboard (wait mode).
ApprovalTimeoutError
class ApprovalTimeoutError(ArdenError):
action_id: str
timeout: floatRaised in wait mode when no human decision is received within max_poll_time seconds.
Error Handling Patterns
Pattern 1: Handle all decisions at the call site (wait mode)
def process_customer_request(amount: float, customer_id: str):
try:
result = safe_refund(amount, customer_id=customer_id)
return {"ok": True, "refund": result}
except arden.PolicyDeniedError:
return {"ok": False, "reason": "refund_not_allowed"}
except arden.ApprovalTimeoutError as e:
return {"ok": False, "reason": "approval_timeout", "action_id": e.action_id}
except arden.ArdenError as e:
logger.error(f"Arden API error: {e}")
return {"ok": False, "reason": "policy_check_failed"}Pattern 2: Deferred handling (async/webhook mode)
# Tool is wrapped once at startup
safe_refund = arden.guard_tool(
"stripe.issue_refund",
issue_refund,
approval_mode="webhook",
on_approval=handle_refund_approved,
on_denial=handle_refund_denied,
)
# At call time, only check for immediate blocks
def process_customer_request(amount: float, customer_id: str):
try:
result = safe_refund(amount, customer_id=customer_id)
except arden.PolicyDeniedError:
return {"ok": False, "reason": "refund_not_allowed"}
if isinstance(result, arden.PendingApproval):
return {"ok": True, "status": "pending", "action_id": result.action_id}
return {"ok": True, "refund": result}Environments
Arden has two isolated environments. Each has its own API endpoint, API keys, agents, policies, and actions.
| Environment | API URL | Key prefix |
|---|---|---|
| Test | https://api-test.arden.sh | arden_test_ |
| Live | https://api.arden.sh | arden_live_ |
Recommended Setup
import os
import ardenpy as arden
# Use test environment in development, live in production.
# The key prefix determines the environment automatically.
arden.configure(api_key=os.environ["ARDEN_API_KEY"])Set ARDEN_API_KEY=arden_test_... in development and ARDEN_API_KEY=arden_live_... in production. No code changes needed.
For the dashboard, API key management, and policy configuration, see app.arden.sh.
For support, contact team@arden.sh.