Skip to main content

Interven — Approvals + Audit for AI Agents. Scan tool calls through policy + risk scoring. Block, redact PII, or route to human approval via Slack.

Project description

interven

Python SDK for IntervenApprovals + Audit for AI Agents. Add human-in-the-loop approval workflows, policy enforcement, and compliance audit trails to any AI agent in 5 lines of code.

pip install interven

Quickstart

from interven import Client

client = Client(api_key="iv_live_...")  # or set INTERVEN_API_KEY env

result = client.scan(
    method="POST",
    url="https://api.bank.com/v1/wire-transfer",
    body={"amount": 25000, "to": "ACME Logistics", "memo": "Q2 invoice"},
)

if result.decision == "ALLOW":
    execute_transfer(original_body)
elif result.decision == "SANITIZE":
    execute_transfer(result.sanitized_body)     # PII redacted
elif result.decision == "REQUIRE_APPROVAL":
    # Agent pauses — Slack notification sent — human approves
    status = client.wait_for_approval(result.approval_id)
    if status.is_approved:
        execute_transfer(original_body)         # approved, proceed
else:
    log_blocked(result.reason_codes)            # DENY

Get an API key at intervensecurity.com (free tier: 1,000 scans/month).

What Interven does

Interven sits between your AI agent and the tools/APIs it calls. Every outbound action is scanned through policy + risk scoring before it executes:

Decision What to do Property
ALLOW Forward the original request result.allowed
DENY Block. reason_codes explain why. result.blocked
SANITIZE Forward result.sanitized_body — PII/secrets redacted result.needs_sanitization
REQUIRE_APPROVAL Pause. Human approves via Slack or Console. Agent resumes. result.needs_approval

REQUIRE_APPROVAL is Interven's unique capability — no other tool supports end-to-end human-in-the-loop with Slack buttons and automatic agent resumption.

Approval workflow

result = client.scan(method="POST", url="...", body={...})

if result.needs_approval:
    print(f"Waiting for approval: {result.approval_id}")

    # Blocks until analyst clicks Approve in Slack or Console
    status = client.wait_for_approval(
        result.approval_id,
        poll_interval=5.0,    # check every 5s
        max_wait=600.0,       # timeout after 10 min
    )

    if status.is_approved:
        print("Approved! Proceeding...")
    elif status.status == "denied":
        print("Denied by analyst.")
    elif status.status == "expired":
        print("Approval expired.")

Configuration

Argument Env var Default
api_key INTERVEN_API_KEY — (required)
gateway_url INTERVEN_GATEWAY_URL https://api.intervensecurity.com
timeout 30.0
agent_id unset (server uses default)
runtime_type "python"

Framework integrations

LangChain / LangGraph — callback handler

from interven_langchain import InterventCallback

agent = create_react_agent(model, tools=[...])
agent.invoke(
    {"messages": [HumanMessage("...")]},
    config={"callbacks": [InterventCallback(api_key="iv_live_...")]},
)

Three lines. Every tool call scanned. DENY/REQUIRE_APPROVAL handled automatically.

See the LangChain reference repo for full examples including the Slack approval demo.

CrewAI — step callback

from interven import Client
from crewai import Agent

interven = Client(runtime_type="crewai")

def step_guard(step):
    for call in step.tool_calls:
        result = interven.scan(
            method="POST",
            url=call.tool_url,
            body=call.payload,
        )
        if result.blocked:
            raise RuntimeError(f"Interven blocked: {result.reason_codes}")

agent = Agent(role="...", goal="...", step_callback=step_guard)

MCP server — middleware

from interven import Client

interven = Client(runtime_type="mcp")

@server.tool_middleware
async def scan_before_call(tool_name, params, next_handler):
    result = interven.scan(
        method="POST",
        url=f"mcp://{tool_name}",
        body=params,
    )
    if result.blocked:
        raise RuntimeError(f"Blocked: {result.reason_codes}")
    return await next_handler(tool_name, params)

Generic agent (AutoGen, OpenAI Assistants, custom)

import requests
from interven import Client

interven = Client()

def safe_post(url, json=None):
    r = interven.scan(method="POST", url=url, body=json or {})
    if r.blocked:
        raise RuntimeError(f"Blocked: {r.reason_codes}")
    if r.needs_approval:
        status = interven.wait_for_approval(r.approval_id)
        if not status.is_approved:
            raise RuntimeError("Approval denied or expired")
    body = r.sanitized_body if r.needs_sanitization else json
    return requests.post(url, json=body)

Errors

from interven import (
    AuthenticationError,      # bad / revoked API key
    GatewayError,             # network or 5xx
    PayloadTooLargeError,     # >256KB body
    ApprovalDeniedError,      # analyst denied
    ApprovalExpiredError,     # approval timed out
    ApprovalTimeoutError,     # poll max_wait exceeded
)

Legacy: HMAC AifClient

The original HMAC-signed /invoke flow is still supported for existing deployments. New integrations should prefer Client — fewer fields, no shared secret.

from interven import AifClient, InvokeParams

client = AifClient(
    gateway_url="http://localhost:4000",
    agent_id="...",
    agent_name="release-bot",
    agent_secret="...",
)

result = client.invoke(InvokeParams(
    tool_name="github",
    method="PUT",
    url_path="/repos/acme/main-app/collaborators/external-user",
    credential_type="pat",
    credential_token="ghp_...",
    scopes=["repo"],
))

License

MIT

Links

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

interven-0.6.1.tar.gz (27.9 kB view details)

Uploaded Source

Built Distribution

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

interven-0.6.1-py3-none-any.whl (25.7 kB view details)

Uploaded Python 3

File details

Details for the file interven-0.6.1.tar.gz.

File metadata

  • Download URL: interven-0.6.1.tar.gz
  • Upload date:
  • Size: 27.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for interven-0.6.1.tar.gz
Algorithm Hash digest
SHA256 29fc22c8557b0becc0317c174307da5989fb1825bcfd75a5ff4bd3654005e66b
MD5 8290a05f839c01e5152c306e9f4daa9e
BLAKE2b-256 1fdd07d9e7505a8ab174a819575a4e8aa60a37b2aad79ce71ce5c65ada66ff30

See more details on using hashes here.

File details

Details for the file interven-0.6.1-py3-none-any.whl.

File metadata

  • Download URL: interven-0.6.1-py3-none-any.whl
  • Upload date:
  • Size: 25.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for interven-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d7792ac8674bee6a61deaa69ad7b1452ed17eee13ab4ba2ae2a29f65b03dbe87
MD5 99bf65c23dc3d8419ae237df58ac4bf9
BLAKE2b-256 707b66b915a54430b116e68c351a7886752442f10b29350ece4d94cb4ae829cd

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