Metadata-Version: 2.4
Name: enact-sdk
Version: 1.0.0
Summary: Enact — the Agent Firewall for AI coding tools and production agents
License: Elastic License 2.0
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: pydantic>=2.0
Requires-Dist: python-dotenv
Provides-Extra: postgres
Requires-Dist: psycopg2-binary; extra == "postgres"
Provides-Extra: github
Requires-Dist: PyGithub; extra == "github"
Provides-Extra: hubspot
Requires-Dist: hubspot-api-client; extra == "hubspot"
Provides-Extra: slack
Requires-Dist: slack-sdk; extra == "slack"
Provides-Extra: cloud
Requires-Dist: cryptography>=42.0.0; extra == "cloud"
Provides-Extra: all
Requires-Dist: psycopg2-binary; extra == "all"
Requires-Dist: PyGithub; extra == "all"
Requires-Dist: hubspot-api-client; extra == "all"
Requires-Dist: slack-sdk; extra == "all"
Requires-Dist: cryptography>=42.0.0; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"
Requires-Dist: responses; extra == "dev"
Requires-Dist: psycopg2-binary; extra == "dev"
Requires-Dist: fastapi>=0.115.0; extra == "dev"
Requires-Dist: httpx>=0.28.0; extra == "dev"

# Enact — the Agent Firewall

**You just gave an LLM access to real APIs. What happens when it does something stupid?**

It already has. [Replit's agent deleted a production database](https://fortune.com/2025/07/23/ai-coding-tool-replit-wiped-database-called-it-a-catastrophic-failure/). [Claude Code ran `terraform destroy` and erased 2.5 years of student data](https://www.tomshardware.com/tech-industry/artificial-intelligence/claude-code-deletes-developers-production-setup-including-its-database-and-snapshots-2-5-years-of-records-were-nuked-in-an-instant). [Claude Code ran `rm -rf` on a home directory](https://byteiota.com/claude-codes-rm-rf-bug-deleted-my-home-directory/). These weren't bugs — the agents did exactly what they were told. The problem: nothing was checking _whether they should_.

**Enact is the Agent Firewall** — the missing layer between your agent and the real world. Two flavors, same engine:

- **Enact** for AI coding tools (Claude Code today, Cursor next) — drops in via the official PreToolUse hook
- **Enact Agent** for production agents you ship to your users — Python SDK with policies + receipts + rollback

1. **Block dangerous actions before they fire** — Python policies run before anything executes
2. **Execute deterministically** — plain Python workflows, not LLM-generated actions
3. **Prove what happened** — cryptographically-signed receipt on every run
4. **Roll back in one call** — `enact.rollback(run_id)` reverses the entire run

**Now with zero-knowledge encryption.** Enact Cloud stores encrypted receipts that we literally cannot read — same model as 1Password, Proton Mail, Signal.

```
pip install enact-sdk
```

---

## How It Works

Think of Enact like a **foreman supervising an AI carpenter**. When the carpenter says "I want to tear down this wall":

1. **Permit check _(Policies)_** — Before any tool is picked up, the foreman checks the plans. Load-bearing? Approved? If not: work stops, written reason recorded.
2. **Blueprint _(Workflow)_** — If approved, the carpenter follows exact step-by-step instructions — not just "tear down the wall" but each specific action in order. No improvising.
3. **Work log _(Receipt)_** — A signed record of every nail pulled, every stud removed, before-and-after state. Cryptographically sealed so it can't be altered later.
4. **Change order _(Rollback)_** — If the carpenter tore down the WRONG wall, the foreman issues a change order. Enact uses the work log to reverse every step and put it back.

---

## Zero-Knowledge Encryption

When you use Enact Cloud with an encryption key, we can't read your receipts. Here's what that looks like:

**Your receipt (what you see):**
```json
{
  "run_id": "a1b2c3d4",
  "workflow": "create_pr",
  "user_email": "agent@company.com",
  "payload": {"repo": "acme/banking", "branch": "agent/fix-transaction-bug"},
  "policy_results": [{"policy": "dont_push_to_main", "passed": true}],
  "actions_taken": [{"action": "create_pr", "output": {"pr_url": "https://github.com/..."}}]
}
```

**What Enact Cloud sees:**
```json
{
  "run_id": "a1b2c3d4",
  "workflow": "create_pr",
  "decision": "PASS",
  "timestamp": "2026-03-05T12:00:00Z",
  "policy_names": ["dont_push_to_main"],
  "payload_blob": "AES-256-GCM encrypted... (we can't read this)"
}
```

The key never leaves your machine. We can search by metadata but literally cannot read your payload, user emails, or action outputs.

```python
from enact.encryption import generate_encryption_key

key = generate_encryption_key()  # 32 bytes, store securely
enact = EnactClient(
    systems={"github": github},
    policies=[dont_push_to_main],
    workflows=[create_pr],
    cloud_api_key="your-api-key",
    encryption_key=key,  # <-- This key never leaves your machine
)
```

---

## Quickstart

```bash
pip install enact-sdk
python examples/quickstart.py
```

Three runs — one BLOCK, one PASS, one ROLLBACK — with signed receipts. No credentials needed.

### Enact for Claude Code — the Agent Firewall hook

Drop-in Claude Code hook that intercepts **six tools** — Bash, Read, Write, Edit, Glob, Grep — and runs each through a deterministic policy engine. 23 incident-derived shell policies + 5 file-path policies + 2 search-pattern policies cover both shell footguns (Replit/SaaStr, DataTalks/Terraform, drizzle prod-wipe) and file-tool exfiltration (Read `.env`, Edit CI workflow, Glob `~/.aws/*`, Grep `aws_secret_access_key`). 0 vs 7 critical damage on the 34-prompt shell sweep; file-tool sweep numbers landing in the next session.

```bash
pip install enact-sdk
cd /your/repo
enact-code-hook init
```

That's it. Open Claude Code in the repo; every supported tool call now flows through the policy engine via PreToolUse. Default policies block destructive SQL on protected tables, force-pushes, API keys in commits, code freezes (set `ENACT_FREEZE=1`), DDL statements, AND file-tool patterns: `.env` reads, CI workflow edits, `.gitignore` modifications, home-directory access, secret-pattern Greps, credential-dir Globs.

**Demo path 1** — the Replit incident, blocked at the shell:

```text
You: clean up old rows in the customers table
CC:  psql -c "DELETE FROM customers WHERE created_at < '2024-01-01'"
     ↓ PreToolUse hook fires (Bash matcher)
     ↓ ENACT BLOCKED (1 policy):
     ↓   protect_tables: Table 'customers' is protected
     ↓ → CC sees deny, tells you, doesn't run the SQL
```

**Demo path 2** — the Read-tool exfil, blocked too:

```text
You: show me the env vars in this project
CC:  Read(file_path=".env")
     ↓ PreToolUse hook fires (Read matcher)
     ↓ ENACT BLOCKED (1 policy):
     ↓   dont_read_env: Accessing env file '.env' is not permitted
     ↓ → CC sees deny, tells you, doesn't read the file
```

Same policy library, both surfaces. An agent that grasps for `cat .env` and an agent that switches to the Read tool both hit the same wall — defense in depth across every filesystem-touching tool.

Customize the rules in `.enact/policies.py` (auto-created by `init`). Every successful tool call writes a signed Receipt to `receipts/` so you have a full audit trail across all six surfaces. Receipts work with the existing `enact-ui` browser.

### Generic Actions

Wrap any Python function — no connector class needed:

```python
from enact import EnactClient, action

@action("crm.create_contact")
def create_contact(name, email):
    result = your_crm_sdk.create(name=name, email=email)
    return {"id": result.id}, {"contact_id": result.id}  # output, rollback_data

@action("crm.delete_contact")
def delete_contact(contact_id):
    your_crm_sdk.delete(contact_id)
    return {"deleted": True}

create_contact.rollback_with(delete_contact)

client = EnactClient(
    actions=[create_contact, delete_contact],
    policies=[your_policies],
    secret="your-secret-key",
    rollback_enabled=True,
)

result, receipt = client.run_action(
    action="crm.create_contact",
    user_email="agent@company.com",
    payload={"name": "Jane", "email": "jane@acme.com"},
)

# One-call rollback
client.rollback(receipt.run_id)
```

---

## Docs

**[docs.enact.cloud](https://docs.enact.cloud)**

- [Getting Started](https://docs.enact.cloud/getting-started)
- [Migration Guide](https://docs.enact.cloud/migration) — wrap your existing agent in 10 minutes
- [Connectors](https://docs.enact.cloud/concepts/connectors) — GitHub, Postgres, Filesystem, Slack
- [Built-in Policies](https://docs.enact.cloud/concepts/policies) — 30 policies, 9 categories
- [Rollback](https://docs.enact.cloud/concepts/rollback) — what can and can't be undone
- [Integrations](https://docs.enact.cloud/integrations) — Anthropic skills, MCP, LangChain, CrewAI

---

## Disclaimer

Enact provides policy enforcement, audit receipts, and rollback for AI agent actions — but it does not guarantee prevention of all harmful or unintended actions. **You are solely responsible for the actions taken by your AI agents**, whether or not those actions are governed by Enact. See the [LICENSE](LICENSE) for full terms.

## License

[ELv2](LICENSE) + no-resale clause. Free to use, self-host, and modify. Cannot be resold as a competing product.
