Skip to main content

ardenpy

Policy enforcement and human approval for AI agent tool calls.

Tests PyPI version Python versions Coverage License: MIT

Arden demo

Arden sits between your agent and its tools. Every call is checked against policies you configure in the dashboard — automatically allowed, blocked, or held for a human to approve.

Install

pip install ardenpy

Claude Code skill

Let Claude Code integrate Arden into your project automatically — it detects your framework, adds the dependency, inserts configure(), and optionally sets up session tracking:

# Add the skill to your project
mkdir -p .claude/commands
curl -o .claude/commands/arden-setup.md \
  https://raw.githubusercontent.com/ardenhq/adenpy/main/skills/arden-setup.md

Then in Claude Code, run:

/arden-setup

Quick start

1. Get your API key from app.arden.sh. You'll get two keys:

  • arden_test_... — development, hits api-test.arden.sh
  • arden_live_... — production, hits api.arden.sh

2. Configure once

import ardenpy as arden
arden.configure(api_key="arden_live_...")

3. Call your tools

For LangChain, CrewAI, and OpenAI Agents SDK — that's it. Arden auto-patches all three frameworks at configure-time, so every tool call is intercepted without any wrapping:

# LangChain, CrewAI, or OpenAI Agents SDK — use tools normally
arden.configure(api_key="arden_live_...")

agent = create_react_agent(llm, tools, prompt)  # no wrapping needed
# Every tool call is now enforced and logged automatically

For custom agents with no framework, wrap functions explicitly:

def issue_refund(amount: float, customer_id: str) -> dict:
    return {"refund_id": "re_123", "amount": amount}

safe_refund = arden.guard_tool("stripe.issue_refund", issue_refund)

result = safe_refund(150.0, customer_id="cus_abc")
# Arden checks policy first — allow, block, or wait for human approval

How it works

Every tool call goes through a policy check before executing:

Policy decision What happens
allow Function executes immediately
block PolicyDeniedError raised, function never runs
requires_approval Pauses until a human approves or denies on the dashboard

No policy configured? The call is allowed automatically and logged — you get a full audit trail from day one and can add policies incrementally.


Approval modes

When a tool requires approval, you choose how your code waits:

wait (default) — blocks until a human acts, then executes or raises PolicyDeniedError.

async — returns a PendingApproval immediately, background thread polls and calls your callback.

webhook — returns PendingApproval immediately, no polling. Arden POSTs to your endpoint when an admin decides.

# wait (default)
safe_refund = arden.guard_tool("stripe.issue_refund", issue_refund)

# async
safe_refund = arden.guard_tool("stripe.issue_refund", issue_refund,
    approval_mode="async", on_approval=handle_approval, on_denial=handle_denial)

# webhook
safe_refund = arden.guard_tool("stripe.issue_refund", issue_refund,
    approval_mode="webhook", on_approval=on_approval, on_denial=on_denial)

For webhook setup (FastAPI, Flask, Django examples) see the Library Reference.


Framework integrations

LangChain, CrewAI, and OpenAI Agents SDK — zero wrapping required

Arden automatically patches all three frameworks when configure() is called. Every tool call in the process is intercepted — including tools created after configure is called.

import ardenpy as arden

arden.configure(api_key="arden_live_...")
# All tool calls are now intercepted, enforced, and logged.
# No protect_tools(), no guard_tool(), no boilerplate.
Framework What gets patched
LangChain BaseTool.run at the class level
CrewAI BaseTool.run at the class level
OpenAI Agents SDK FunctionTool.__init__ — wraps on_invoke_tool per instance

Tool names in the dashboard match each tool's .name attribute. If you don't already have the framework installed, install it alongside ardenpy:

pip install ardenpy langchain-core                   # LangChain
pip install ardenpy crewai                           # CrewAI
pip install ardenpy openai-agents                    # OpenAI Agents SDK

OpenAI Chat Completions (raw loop)

The Chat Completions API has no patchable base class. Use ArdenToolExecutor to register and dispatch tool calls:

from ardenpy.integrations.openai import ArdenToolExecutor

executor = ArdenToolExecutor()
executor.register("issue_refund", issue_refund_fn)
executor.register("send_email",   send_email_fn)

# In your tool-call loop:
result = executor.run(tc.function.name, json.loads(tc.function.arguments))

See examples/ for runnable code for every integration.


Session tracking

Attach a session ID to group all tool calls from a single conversation in the action log:

import ardenpy as arden
import uuid

arden.configure(api_key="arden_live_...")

# Set once per request — all guard_tool and auto-patched calls carry it automatically
arden.set_session(str(uuid.uuid4()))

Uses contextvars.ContextVar — safe for concurrent async requests. Fully optional.


Token usage tracking

Arden automatically tracks token usage and estimated cost for every LLM call — no extra setup needed. For LangChain, CrewAI, and the OpenAI Agents SDK, configure() captures usage from the framework at runtime and sends it to the dashboard in a background thread (zero latency impact).

import ardenpy as arden

arden.configure(api_key="arden_live_...")
# Token usage is now tracked automatically alongside tool calls.
# View cost breakdowns by model, day, and session in the dashboard.

For custom agent loops where you call the LLM directly, log usage manually:

response = openai_client.chat.completions.create(
    model="gpt-4o",
    messages=messages,
)
arden.log_token_usage(
    model="gpt-4o",
    prompt_tokens=response.usage.prompt_tokens,
    completion_tokens=response.usage.completion_tokens,
)
What gets tracked Automatically?
LangChain (BaseChatModel) Yes — auto-patched by configure()
CrewAI Yes — uses LangChain under the hood
OpenAI Agents SDK (Runner.run) Yes — auto-patched by configure()
OpenAI Chat Completions (raw loop) Manual — call arden.log_token_usage()
Any other LLM Manual — call arden.log_token_usage()

The dashboard shows cost broken down by model, day, and session — all scoped per agent.


Error handling

try:
    result = safe_refund(150.0, customer_id="cus_abc")
except arden.PolicyDeniedError:
    # blocked by policy, or denied by a human
except arden.ApprovalTimeoutError:
    # nobody approved within max_poll_time (wait mode)
except arden.ArdenError:
    # API/configuration error

Links

Metadata

Release files for ardenpy 0.5.7

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

Source distribution (sdist)

Source distribution for ardenpy 0.5.7
File Size Uploaded Provenance
ardenpy-0.5.7.tar.gz 55.2 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 87.3 kB

Release files / ardenpy-0.5.7.tar.gz

Download URL ardenpy-0.5.7.tar.gz
Size 55.2 kB
Tags Source
SHA-256 checksum
How to use checksums
10c56470753b70dfb2a62b83feb4ec0c0f2735bc2cedd8979ba81f6741752064
BLAKE2b-256 checksum
How to use checksums
beeb539796e437b69bc737cd80f45fc5e4bc59765dffd5031294f0c19d29680a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / ardenpy-0.5.7-py3-none-any.whl

Download URL ardenpy-0.5.7-py3-none-any.whl
Size 32.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b46fba55cdb299a820cc22cbd327883fd70ded049439835b3eff1024fd80766b
BLAKE2b-256 checksum
How to use checksums
cfe4857c544de10a6d79269982f274b072fd9ed48582a95dee0917e2a344016f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Security for ardenpy 0.5.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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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