Metadata-Version: 2.5
Name: agentgovern
Version: 2.6.0
Summary: Compliance-as-code middleware for agentic AI workflows.
Project-URL: Homepage, https://agentgovern.zirahn.com
Project-URL: Repository, https://github.com/ahmedkhan-zirahn/agentgovern
Project-URL: Issues, https://github.com/ahmedkhan-zirahn/agentgovern/issues
Author-email: Ahmed Khan <ahmed.khan@zirahn.com>
License: MIT
License-File: LICENSE
Keywords: agent-governance,agents,ai,compliance,eu-ai-act,governance,langchain,nist
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.10.0
Provides-Extra: crewai
Requires-Dist: crewai>=0.80.0; extra == 'crewai'
Provides-Extra: dev
Requires-Dist: langchain>=1.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
Requires-Dist: pytest>=8.3.0; extra == 'dev'
Requires-Dist: respx>=0.21.0; extra == 'dev'
Requires-Dist: ruff>=0.8.0; extra == 'dev'
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.3.0; extra == 'langchain'
Provides-Extra: langgraph
Requires-Dist: langchain-core>=0.3.0; extra == 'langgraph'
Requires-Dist: langgraph<2.0.0,>=0.2.0; extra == 'langgraph'
Provides-Extra: openai
Requires-Dist: openai>=1.50.0; extra == 'openai'
Provides-Extra: sdk
Description-Content-Type: text/markdown

# AgentGovern Python SDK

**Compliance-as-code for agentic AI workflows.**

> **Beta** — API may change before 1.0. [Report issues](https://github.com/ahmedkhan-zirahn/agentgovern/issues).

AgentGovern intercepts AI agent actions, evaluates them against configurable compliance policies (the EU AI Act today; NIST AI RMF and ISO 42001 are on the roadmap — see the table below), and generates audit-ready evidence in near real-time. Tracking runs in a background thread and fails open. An `enforce`-mode block raises in your code (see *Enforcement modes* below for exactly what it stops). *(Corrected again 2026-10-03: the first correction said "the SDK blocks only if you enable Gate 2 `enforce` mode, where a block verdict raises `OutputBlocked`", which reads as if enforce mode halts an agent; through the integrations it does not — NAGT-380.)* This SDK auto-instruments LangChain and LangGraph; any other framework (CrewAI, OpenAI Agents and the rest) can report actions with `track_action()`. *(Corrected 2026-10-03: this said NIST AI RMF and ISO 42001 were supported, that the SDK never blocks, and that it instruments CrewAI and OpenAI Agents code.)*

## Install

```bash
pip install "agentgovern[langchain]"
```

## Quickstart — LangChain

```python
import agentgovern
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI

# 1. Initialize once at startup
agentgovern.init(
    api_key="ag_prod_...",           # from https://agentgovern.zirahn.com/settings/api-keys
    base_url="https://agentgovern.zirahn.com",
    environment="development",       # "production" | "staging" | "development"
)

# 2. Register your agent
agentgovern.register_agent(
    external_id="credit-scoring-v2",
    name="Credit Scoring Agent v2",
    framework="langchain",
)

# 3. Get the callback handler — binds to credit-scoring-v2 automatically
handler = agentgovern.instrument_langchain()

# 4. Build the agent and pass the handler via config — no other changes needed
agent = create_agent(model=ChatOpenAI(model="gpt-4o"), tools=tools)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "Evaluate loan application for customer #12345"}]},
    config={"callbacks": [handler]},
)
```

`instrument_langchain()` binds to the most recently registered agent. Every tool call,
LLM invocation, and agent step is captured, evaluated against your compliance policies,
and visible in the dashboard.

## Enforcement modes

AgentGovern supports four enforcement modes per policy:

| Mode     | Behavior                                                   |
|----------|------------------------------------------------------------|
| warn     | Records the violation; the agent continues                 |
| log      | Records the violation silently; the agent continues        |
| disabled | Policy not evaluated                                       |
| enforce  | Records the violation and **raises** in your code (below)  |

### What enforce stops, through the LangChain and LangGraph integrations

When an enforce-mode policy blocks, the exception reaches the code that called
`invoke()`, `ainvoke()`, `stream()` or `astream()`:

- **Gate 1 (input) raises `PolicyViolation` before the model call runs.** This is the
  control that stops an agent before it acts.
- **Gate 2 (output) raises `OutputBlocked` (block) or `OutputEscalated` (escalate)**
  when the run finishes. Gate 2 stops `invoke()` from **returning** a blocked answer.
  **It does not undo anything that already happened:** tool calls have already run, a
  LangGraph checkpointer has already saved the final state, and a `stream()` caller has
  already received the streamed output. On LangChain, a run whose LLM streamed tokens skips the synchronous Gate 2 entirely.
- **Redact** replaces the answer on LangChain; LangGraph does not apply it.

**What never stops your agent:** warn, log and allow verdicts; AgentGovern being
unreachable, slow, or returning an error (unless you configured `fail_open=False`, in
which case Gate 1 raises `GateUnavailable`, or `gate_2_failure_mode="fail_closed"`, in
which case Gate 2 raises `OutputBlocked`); and any error inside the SDK itself.

**Pass AgentGovern's handler last.** When an enforce block raises, LangChain can stop
delivering that event to the handlers after ours in the `callbacks` list (on synchronous
runs it always does). A tracing or logging handler placed after AgentGovern's might not
see the event that was blocked.
Put AgentGovern's handler at the end of the list:
`config={"callbacks": [your_tracer, agentgovern_handler]}`.

**How:** an instrumentor sets LangChain's `raise_error` when an enforce gate is
configured (Gate 2 `enforce`, or Gate 1 auto-evaluation on), and lets only the three
verdict exceptions above out of its callbacks.

*(Changed in SDK 2.6.0, NAGT-380. Earlier releases recorded enforce-mode violations
but did not stop the agent: LangChain caught the exception.)*

You can also check input yourself before invoking an agent:

```python
result = agentgovern.evaluate_input(agent_external_id="my-agent", prompt=user_prompt)
if result.action_taken == "block":
    raise HTTPException(status_code=403, detail="Prompt blocked by compliance policy")
agent.invoke({"input": user_prompt})
```

## Multiple agents in one process

If you run more than one agent in the same process, pass the agent ID explicitly to
avoid ambiguity:

```python
agentgovern.register_agent("fraud-detector", name="Fraud Detector")
agentgovern.register_agent("kyc-agent", name="KYC Agent")

handler_fraud = agentgovern.instrument_langchain("fraud-detector")
handler_kyc   = agentgovern.instrument_langchain("kyc-agent")

fraud_agent = create_agent(model=..., tools=...)
kyc_agent   = create_agent(model=..., tools=...)

fraud_agent.invoke(inputs, config={"callbacks": [handler_fraud]})
kyc_agent.invoke(inputs, config={"callbacks": [handler_kyc]})
```

## Manual instrumentation (all frameworks)

```python
from agentgovern.types import ActionType, ActionStatus

agentgovern.track_action(
    agent_external_id="my-agent-id",
    action_type=ActionType.TOOL_CALL,
    action_name="fetch_credit_bureau_data",
    status=ActionStatus.COMPLETED,
    duration_ms=312,
    input_payload={"bureau": "experian", "customer_id": "..."},
    output_payload={"fico_score": 720},
)
```

## Supported frameworks

| Framework | Auto-instrumentation | Status |
|-----------|---------------------|--------|
| LangChain | `instrument_langchain()` — wraps tool and LLM callbacks | Stable |
| CrewAI | Manual via `track_action()` | Beta |
| OpenAI Agents API | Manual via `track_action()` | Beta |

Auto-instrumentation for CrewAI and OpenAI Agents is on the roadmap.

## Compliance frameworks

| Framework | Status |
|-----------|--------|
| EU AI Act (High-Risk Systems) | Available |
| NIST AI RMF | Coming soon |
| ISO 42001 | Coming soon |

Enable policy packs from the [AgentGovern dashboard](https://agentgovern.zirahn.com).

## Configuration

| Parameter | Default | Description |
|-----------|---------|-------------|
| `api_key` | required | SDK ingest key from the dashboard |
| `base_url` | `https://agentgovern.zirahn.com` | API endpoint |
| `environment` | `"production"` | `"production"` \| `"staging"` \| `"development"` |
| `policy_engine_url` | `https://engine.zirahn.com` | Policy engine endpoint for Gate 1 (`evaluate_input`) and Gate 2 checks. Override with this argument or the `AGENTGOVERN_POLICY_ENGINE_URL` env var |
| `fail_silently` | `True` | If `True`, SDK errors never raise into your agent |

**Policy engine address (2.4.0).** The default engine address is now the stable name
`https://engine.zirahn.com`. Versions 2.3.0 and earlier call `https://agentgovern.onrender.com`
directly. That address keeps working, so nothing breaks if you stay on an older version, but only
the stable name can follow the engine if it moves. Upgrade with `pip install --upgrade agentgovern`.
If you set `policy_engine_url` or `AGENTGOVERN_POLICY_ENGINE_URL` yourself, it still takes precedence.

## Claude Code Hook

The SDK ships a built-in CLI for installing the AgentGovern hook into Claude Code. The hook
intercepts `PreToolUse` events for every tool call and enforces your tenant policies in real
time — before the tool executes. A tool AgentGovern doesn't yet have a specific classification
for is still captured and evaluated, tagged `action_type=unmapped_tool` rather than silently
skipped.

### Install

```bash
agentgovern hook install
```

This deploys the hook script to `~/.agentgovern/hook.py`, merges the correct entry into
`~/.claude/settings.json` (with an atomic backup), and prints instructions for any missing
env vars.

### Upgrading an existing install

Upgrading the package does **not** update a hook that is already installed. `hook install`
copies the hook script to `~/.agentgovern/hook.py` and writes its entries into
`~/.claude/settings.json`, and a plain `agentgovern hook install` against an existing install
reports it as already installed and changes nothing. Upgrade, read what is installed now, then
reinstall with `--force`:

```bash
python3 -m pip install --upgrade agentgovern   # or the extra you installed with, e.g. "agentgovern[langchain]"
agentgovern hook status                        # note each line's cmd= value and the "Install mode" line
agentgovern hook install --force               # plus the flags below, if status calls for them
agentgovern hook status                        # reports no [DRIFT] lines once the hook is current
```

**`--force` writes the current defaults. It does not remember options from the earlier install**,
so repeat what `hook status` showed:

- **`cmd=` is anything other than plain `python3`** (for example `cmd=/opt/local/bin/python3.12`):
  add `--python-command <that exact value>`. Without it, `--force` resets the hook to `python3`.
- **`Install mode: minimal`:** add `--capture-mode=minimal`. Without it, `--force` turns a minimal
  install into a full one.
- **You once passed `--matcher`:** pass it again.

Your environment variables are not touched. Restart any running Claude Code session afterwards.

**If a command isn't found:**

- **`pip: command not found`:** use `python3 -m pip`, as above.
- **`agentgovern: command not found`** (the command was installed somewhere that isn't on your
  `PATH`), or pip refuses with `externally-managed-environment`: install the CLI into its own
  virtual environment and call it by its full path:

  ```bash
  python3 -m venv ~/.agentgovern-venv
  ~/.agentgovern-venv/bin/python -m pip install --upgrade agentgovern
  ~/.agentgovern-venv/bin/agentgovern hook status
  ~/.agentgovern-venv/bin/agentgovern hook install --force   # plus the flags status called for
  ```

  **The venv holds only the CLI.** The hook itself runs with the interpreter recorded in
  `~/.claude/settings.json` (the `cmd=` value in `hook status`; `python3` unless you chose
  otherwise). That interpreter needs no packages, because the hook script uses only the standard
  library, and **installing from a venv does not change it** unless you pass `--python-command`.

**If your hook was installed by 2.2.1 or earlier, this step matters for coverage, not just
freshness.** Those versions wrote a `PreToolUse` matcher naming a fixed list of tools (ten, in 2.2.1), so a call
through any other tool (`PowerShell`, for example) never reached the hook. Starting with 2.3.0
the matcher is `*`, every tool — but only once `hook install --force` has rewritten the entry.

### Required env vars

```bash
export AGENTGOVERN_API_KEY="ag_prod_..."           # Settings → API Keys
export AGENTGOVERN_ACTOR_USER_ID="<your-actor-id>"  # from your install snippet: Settings → Developers (see the hook README)
```

### Subcommands

| Command | Description |
|---|---|
| `agentgovern hook install` | Install the hook (flags: `--dry-run`, `--force`, `--matcher`, `--python-command`) |
| `agentgovern hook uninstall` | Remove the hook entry from `settings.json` (script file preserved) |
| `agentgovern hook status` | Show installation state, script path, and env var status |
| `agentgovern hook test` | Fire a synthetic event to verify end-to-end connectivity |

### Bypass

To skip governance for a session without removing the hook:

```bash
AGENTGOVERN_HOOK_MODE=off claude
```

See `packages/claude-hook/README.md` for the full option reference.

## Design guarantees

- `track_action()` does not wait on the network — all I/O happens in a background thread. *(Corrected 2026-10-03: this said "returns in < 5 ms", a figure no benchmark in this repository measures.)*
- Buffer cap: 10,000 actions; oldest dropped when full
- Retry: 3 attempts with exponential backoff (1 s → 30 s max)
- If AgentGovern is unreachable, your agent continues unaffected

## Links

- **Dashboard:** https://agentgovern.zirahn.com
- **Documentation:** https://github.com/ahmedkhan-zirahn/agentgovern
- **Issues:** https://github.com/ahmedkhan-zirahn/agentgovern/issues

## License

MIT — Copyright (c) 2026 Zirahn
