Metadata-Version: 2.4
Name: truceptor
Version: 0.5.0
Summary: Truceptor — trusted intercept for agent tool calls: allow/deny/escalate (does not execute tools).
Author: SV
License-Expression: MIT
Keywords: ai,agents,governance,policy,opa,control-plane,mcp,audit
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
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
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.33.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Requires-Dist: pip-audit>=2.7; extra == "dev"
Requires-Dist: bandit>=1.7; extra == "dev"
Dynamic: license-file

# Truceptor (Python SDK)

**Truceptor** — trusted intercept for agent tool calls: preflight allow/deny/escalate; your runtime executes tools after allow.

> CLI: **`acp up`**, **`acp init`** (also **`truceptor up`**). Install: **`pip install truceptor`**.

> **Import:** `from truceptor import governed_tool, ACPClient`. Env vars use `ACP_*` (`ACP_INTERCEPTOR_URL`, etc.). User data dir stays **`~/.acp/`**.

**Add governance, approvals, policy enforcement, and execution visibility to AI agents in minutes.**

Works with CrewAI, LangGraph, Strands, Google ADK, MCP tools, and custom Python workflows.

**Requires:** [Docker Desktop](https://docs.docker.com/get-docker/) (Compose v2).

**Full integration guide:** [docs/INTEGRATION.md](https://github.com/raja-datascientist/truceptor/blob/main/docs/INTEGRATION.md) (setup vs runtime, Rego → Postgres, pip paths, who owns what).

---

## Quick start

Make sure Docker Desktop is already running before you start Truceptor (`acp up`).

```bash
pip install truceptor
acp init          # ~/.acp/policies + ~/.acp/agents.json
acp up            # Open mode (default)
acp dashboard
```

| Mode | Command |
|------|---------|
| **Open** (default) | `acp up` |
| **Seeded** | `acp up --register` |
| **Enforced** | `AGENT_REGISTRY_ENFORCE=true acp up` |
| Check mode | `acp mode` |

| Step | Command |
|------|---------|
| Install | `pip install truceptor` |
| Initialize policies | `acp init` |
| Start stack | `acp up` |
| Open UI | `acp dashboard` → http://localhost:3090/dashboard/ |
| Stop | `acp down` |

For a real local integration, the usual sequence is:

1. `acp init`
2. start Docker Desktop
3. `acp up`
4. `export ACP_INTERCEPTOR_URL=http://localhost:8080`
5. `export ACP_BEARER_TOKEN=...`
6. run your governed agent

If Docker is not already running, `acp up` will fail with Docker daemon / compose connection errors.

### What `acp init` and `acp up` actually do

| Step | What you get |
|------|----------------|
| **`acp init`** | Creates `~/.acp/policies/` with starter Rego (`router.rego`, `rbac.rego`, …) and `HOW_TO_ADD_RULES.md`. **You edit these files** — Truceptor does not generate rules from your agent code. |
| **`acp up`** | Starts Postgres, OPA, interceptor, dashboard. On startup the interceptor **loads your `~/.acp/policies`**, **upserts** them into Postgres, and **pushes** them to OPA. |
| **Your agent** | Sends only `agent_id`, `tool`, `action`, and context to `POST /tool-call` — **never Rego text**. |

After changing any `.rego` file: `acp down && acp up`. The dashboard **Policies** tab is **read-only** and shows **plain-English rule summaries** (Rego bundle and Policy Studio policies). Business users can author rules in the **Policy Studio** tab (Save & activate); compiled Rego lands in the same Postgres `policy_versions` pipeline.

### Policy Studio (dashboard)

| Step | What you get |
|------|----------------|
| **Policy Studio → New rule** | Wizard: rule type → configure thresholds → simulate → Save & activate |
| **Activate** | Compiler writes `studio/*.rego` + `studio_router.rego` into **`policy_versions`** and syncs OPA |
| **Policies tab** | Same catalog API — studio policies tagged **Policy Studio**, engineer modules tagged **Rego bundle** |

See [docs/POLICY_STUDIO.md](https://github.com/raja-datascientist/truceptor/blob/main/docs/POLICY_STUDIO.md).

---

## Where your policies live (pip install)

The Python package installs into your **virtualenv** (`.venv`). Your **editable Rego files do not** — they live in your home directory:

| What | Location |
|------|----------|
| Installed package (read-only) | `.venv/.../site-packages/truceptor/` |
| **Your policy folder** | **`~/.acp/policies/`** (created by `acp init`) |
| Dev JWT keys | `~/.acp/jwt/` |
| Docker runtime bundle | `~/.acp/runtime/<version>/` |

`acp init` **copies starter templates** from the package into `~/.acp/policies/`. **You edit those files** for your tools, roles, and allow/deny/escalate rules.

`acp up` **bind-mounts** `~/.acp/policies` into the interceptor container. On startup Truceptor **upserts** them into **Postgres**, then **pushes** to **OPA**. Nothing is uploaded from your agent at runtime.

Use a client repo instead of `~/.acp/policies`:

```bash
export ACP_POLICIES_DIR=/path/to/my-project/policies
acp init && acp up
```

**Two phases:** (1) **Setup** — write Rego, run `acp up`; (2) **Runtime** — SDK sends `agent_id`, `tool`, `action` only. See the [integration guide](https://github.com/raja-datascientist/truceptor/blob/main/docs/INTEGRATION.md).

---

## Why Truceptor?

Most agents call tools, APIs, and other agents directly. Teams then scatter rules across Python, workflows, and frameworks:

```python
if supplier_risk_score > threshold:
    require_human_approval()
```

That becomes inconsistent, hard to audit, easy to bypass, and duplicated everywhere.

**Truceptor** centralizes governance **outside** agent code:

| Capability | What you get |
|------------|----------------|
| **Centralized governance** | One place for rules, not copy-paste per team |
| **Policy enforcement** | OPA/Rego evaluates every governed call |
| **Approvals** | Escalate high-risk actions to humans |
| **A2A governance** | Governed agent-to-agent calls |
| **A2T governance** | Governed agent-to-tool calls |
| **Audit & visibility** | Decisions, traces, registry in one dashboard |

---

## Architecture

![Truceptor architecture](https://raw.githubusercontent.com/raja-datascientist/acp-docs/refs/heads/main/images/acp-architecture.svg)

```text
Agent runtime -> Truceptor SDK -> Interceptor / Gateway -> OPA / Rego -> allow | deny | escalate -> governed execution

Policy lifecycle (startup): PostgreSQL policy_versions -> interceptor -> PUT /v1/policies -> OPA in-memory cache
Runtime audit: decisions and traces -> PostgreSQL; dashboard reads catalog and forensics from interceptor APIs
```

```text
SETUP (acp init + acp up)
  ~/.acp/policies/*.rego  ──mount──►  interceptor container
        │
        ▼
  Upsert → Postgres (policy_versions) → push → OPA

RUNTIME (every tool call)
  Agent + SDK  ──POST /tool-call──►  Interceptor  ──►  OPA  ──►  allow | deny | escalate
        (agent_id, tool, action — no Rego in request)
```

Truceptor sits at the execution boundary:

- agent frameworks keep reasoning and orchestration
- **PostgreSQL** is the source of truth for Rego policies, audit events, agents, and approvals
- on startup the interceptor loads **your `~/.acp/policies`** plus built-in platform samples, **upserts to Postgres**, then **syncs to OPA**
- the interceptor validates identity, routes policy, and records audit traces
- OPA / Rego returns deterministic allow, deny, or escalate decisions against synced rules
- only allowed or approved requests reach tools, APIs, MCP servers, or other agents

## Request sequence

![Truceptor governed request sequence](https://raw.githubusercontent.com/raja-datascientist/acp-docs/refs/heads/main/images/acp-sequence.svg)

Typical governed flow:

1. **On interceptor startup:** load active Rego from Postgres and sync to OPA via the Policy API
2. the agent calls a governed function through the Truceptor SDK
3. the interceptor validates JWT identity and normalizes the request
4. OPA / Rego evaluates policy for the tool, action, and claims (in-memory rules synced from Postgres)
5. Truceptor records the decision in Postgres and exposes it in the dashboard
6. the SDK executes only on `allow`, waits for review on `escalate`, and blocks on `deny`

---

## Dashboard

The **Truceptor** governance dashboard is a core differentiator: live allow/deny/escalate decisions, approvals, agent registry, and policy catalog. Open **http://localhost:3090/dashboard/** after `acp up`.

### Overview & activity

![Overview — governance posture and live activity](https://raw.githubusercontent.com/raja-datascientist/acp-docs/refs/heads/main/images/dashboard-overview.png)

### Decisions & approvals

![Governance decisions — allow / deny / escalate analytics](https://raw.githubusercontent.com/raja-datascientist/acp-docs/refs/heads/main/images/dashboard-governance-decisions.png)

![Approvals — human-in-the-loop escalation queue](https://raw.githubusercontent.com/raja-datascientist/acp-docs/refs/heads/main/images/dashboard-approvals.png)

### Registry & policies

![Governance registry — how each agent is governed](https://raw.githubusercontent.com/raja-datascientist/acp-docs/refs/heads/main/images/dashboard-governance-registry.png)

![Policies — Rego catalog from Postgres policy store](https://raw.githubusercontent.com/raja-datascientist/acp-docs/refs/heads/main/images/dashboard-policies.png)

### Forensics & replay

![Forensics Studio — timeline search and audit export](https://raw.githubusercontent.com/raja-datascientist/acp-docs/refs/heads/main/images/dashboard-forensics.png)

![Traces — governance trace investigation](https://raw.githubusercontent.com/raja-datascientist/acp-docs/refs/heads/main/images/dashboard-traces.png)

![Replay — policy simulation against historical input](https://raw.githubusercontent.com/raja-datascientist/acp-docs/refs/heads/main/images/dashboard-replay.png)

---

## Deployment modes

| Mode | How | Best for |
|------|-----|----------|
| **Local** | `acp up` via pip + Docker | Demos, dev, quickstart |
| **SDK** | `@governed_tool` in your agent code | CrewAI, LangGraph, Strands, custom Python |
| **Gateway** | Single origin on `:3090` (dashboard + API proxy) | Local unified URL; pattern for prod ingress |
| **Cloud / self-hosted** | Docker Compose, Kubernetes, ECS/EKS on AWS/Azure/GCP | Team or enterprise rollout |

**Local endpoints**

| URL | Purpose |
|-----|---------|
| http://localhost:3090/dashboard/ | Governance dashboard |
| http://localhost:8080 | Interceptor API (`/tool-call`, `/api/v1/*`) |

**Self-hosted (example)**

```text
https://acp.your-company.example
```

---

## Example: governed tool

Set `ACP_INTERCEPTOR_URL` and `ACP_BEARER_TOKEN` **before** defining a `@governed_tool`.

The decorator constructs its client at decoration time, so setting those env vars later inside `main()` is too late.

```python
import os
from truceptor import governed_tool

# Set env vars before decorator evaluation.
os.environ.setdefault("ACP_INTERCEPTOR_URL", "http://localhost:8080")
os.environ.setdefault("ACP_BEARER_TOKEN", "<dev-jwt>")

@governed_tool(
    agent_id="texas-weather-agent",
    tool="weather_api",
    action="read_weather",
)
def get_texas_weather(city: str):
    return {"city": city, "status": "pending_review"}
```

Truceptor intercepts the call, evaluates policy, then allows, denies, or escalates.

`tool="weather_api"` is the governed tool id. It does **not** have to match the Python function name (`get_texas_weather`). Policy keys on `tool`, not the Python symbol name.

The JWT `agent_id` claim must match `agent_id="texas-weather-agent"` in `@governed_tool(...)`.

---

## Example: policy (Rego)

```rego
package acp.policy

allow {
    input.identity.role == "supply-chain-manager"
    input.action.tool == "supplier_approval"
    input.risk_score < 70
}
```

Edit policies in `~/.acp/policies/` after `acp init`, then restart with `acp down && acp up` so the interceptor upserts them into Postgres and syncs to OPA. See [HOW_TO_ADD_RULES.md](HOW_TO_ADD_RULES.md) in that folder after init.

---

## Adding a new governed tool

`acp init` creates starter policy files in `~/.acp/policies/`, but you still need to wire new tools into policy yourself.

For a brand-new governed tool, update all of these:

1. choose a governed tool id, for example `weather_api`
2. add tool-to-role mapping in `~/.acp/policies/rbac.rego`
3. route the tool in `~/.acp/policies/router.rego`
4. add or reuse a domain policy file such as `weather.rego`
5. mint and export `ACP_BEARER_TOKEN`
6. make sure the JWT `agent_id` claim matches `@governed_tool(agent_id=...)`
7. restart: `acp down && acp up` (loads Rego into Postgres + OPA)
8. run the agent

Two valid patterns:

### Pattern 1: reuse a governed tool bucket

Use one tool id for multiple Python functions in the same policy domain.

```python
@governed_tool(
    agent_id="texas-weather-agent",
    tool="weather_api",
    action="read_weather",
)
def get_texas_weather(city: str):
    ...
```

`~/.acp/policies/rbac.rego`

```rego
"weather_api": ["weather"],
```

`~/.acp/policies/router.rego`

```rego
decision = weather.decision {
    input.tool == "weather_api"
    rbac.decision.decision == "allow"
}
```

`~/.acp/policies/weather.rego`

```rego
package acp.weather

default decision = {
    "decision": "allow",
    "reason": "weather_action_allowed",
    "policy": "acp/weather",
}

decision = {
    "decision": "deny",
    "reason": "weather_action_not_permitted",
    "policy": "acp/weather",
} {
    not input.action == "read_weather"
    not input.action == "read_weather_batch"
}
```

### Pattern 2: add a brand-new governed tool id

If you want policy to key directly on a new id such as `get_texas_weather`, add that id to both `rbac.rego` and `router.rego`, then route it to the right domain policy file.

If your starter `router.rego` or `rbac.rego` references a tool id, make sure the corresponding domain policy file also exists.

---

## Local JWT dev example

Local governed `/tool-call` requests require a bearer token when JWT auth is enabled. `ACP_INTERCEPTOR_URL` alone is not enough.

Set:

- `ACP_INTERCEPTOR_URL=http://localhost:8080`
- `ACP_BEARER_TOKEN=<signed-jwt>`

If `ACP_BEARER_TOKEN` is missing, governed calls may fail with `401 Unauthorized` / `missing bearer token`.

One dev-friendly way to mint a token is:

```bash
python -m pip install pyjwt cryptography

export ACP_BEARER_TOKEN="$(
python - <<'PY'
from pathlib import Path
import time
import jwt

private_key = (Path.home() / ".acp" / "jwt" / "private.pem").read_text()
token = jwt.encode(
    {
        "sub": "agent:texas-weather-agent",
        "agent_id": "texas-weather-agent",
        "roles": ["weather"],
        "iss": "acp-dev",
        "aud": "acp-interceptor",
        "exp": int(time.time()) + 3600,
    },
    private_key,
    algorithm="RS256",
)
print(token)
PY
)"
```

Use these claims for local development:

- `sub=agent:texas-weather-agent`
- `agent_id=texas-weather-agent`
- `roles=["weather"]`
- `iss=acp-dev`
- `aud=acp-interceptor`

`agent_id` in the JWT must match the `agent_id` passed to `@governed_tool(...)`.

---

## Example: governance flow

```text
Supply Chain Agent
    → Truceptor validates identity (JWT)
    → OPA evaluates policy
    → Decision: ESCALATE
    → Human approves in dashboard
    → Execution resumes
```

---

## What Truceptor provides

- **Policy enforcement** — OPA/Rego (Cedar on roadmap)
- **Identity** — JWT from Okta, Auth0, Keycloak, or your IdP
- **Approvals** — human-in-the-loop for risky actions
- **Observability** — dashboard for decisions, traces, agents, tools
- **Agent registry** — lightweight catalog of agents and capabilities
- **Framework-friendly** — keep CrewAI / LangGraph / Strands for reasoning; govern execution here

---

## Philosophy

Orchestration frameworks handle **reasoning, planning, and workflows**.

**Truceptor** handles **governance, trust, approvals, policy, and auditability**.

Reasoning stays autonomous. Execution stays governed.

---

## Roadmap

- **Policy Studio** — **MVP shipped in 0.5.0:** Approval, Risk, and Compliance threshold rules via dashboard wizard; compiles to Rego in `policy_versions`; human-readable Policies tab for all modules.
- Access rules and agent-to-agent rules (Policy Studio)
- Enterprise topology views
- Multi-cloud deployment templates

---

## Release notes

### 0.5.0

- **Breaking (Python import):** package directory renamed `acp` → `truceptor`. Use `from truceptor import governed_tool, ACPClient`. CLI unchanged (`acp up`, `acp init`); env vars still `ACP_*`; user dir still `~/.acp/`.
- **Policy Studio MVP** in bundled interceptor + dashboard: business rules → Rego → same Postgres/OPA pipeline.
- **Policies catalog:** human-readable rule summaries for engineer-authored and Policy Studio modules.
- Bundled runtime sync excludes monorepo-only `deployments/` dev scripts from the PyPI wheel.

### 0.4.x

- PyPI package `truceptor`; integration docs; bundled Docker runtime via `acp up`.

---

## License

MIT License
