Metadata-Version: 2.4
Name: leash
Version: 0.2.0
Summary: Leash – AI Agent Identity, Authorization, and Audit Layer
Author: Chad Eckles
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/chadeckles/leash
Project-URL: Repository, https://github.com/chadeckles/leash
Project-URL: Documentation, https://github.com/chadeckles/leash#readme
Project-URL: Issues, https://github.com/chadeckles/leash/issues
Project-URL: Changelog, https://github.com/chadeckles/leash/blob/main/CHANGELOG.md
Keywords: ai,agents,authorization,audit,security,mcp,langchain,crewai,policy,openclaw,guardrails
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastapi>=0.104.0
Requires-Dist: uvicorn[standard]>=0.24.0
Requires-Dist: sqlalchemy>=2.0.0
Requires-Dist: pyjwt>=2.8.0
Requires-Dist: cryptography>=41.0.0
Requires-Dist: pyyaml>=6.0.1
Requires-Dist: pydantic>=2.5.0
Requires-Dist: httpx>=0.25.0
Provides-Extra: dev
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Dynamic: license-file

<p align="center">
  <img src="assets/leash.png" alt="Leash – Keep your AI agents on a leash" width="700">
</p>

<p align="center">
  <a href="https://pypi.org/project/leash/"><img src="https://img.shields.io/pypi/v/leash?color=blue" alt="PyPI"></a>
  <a href="https://github.com/chadeckles/leash/actions/workflows/tests.yml"><img src="https://github.com/chadeckles/leash/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
  <a href="https://github.com/chadeckles/leash/actions/workflows/docker.yml"><img src="https://github.com/chadeckles/leash/actions/workflows/docker.yml/badge.svg" alt="Docker"></a>
  <a href="https://github.com/chadeckles/leash/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License"></a>
  <a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.11%2B-blue.svg" alt="Python 3.11+"></a>
</p>

# Leash

**Keep your AI agents on a leash.**

You wouldn't let a dog roam the neighborhood unsupervised — so why let an AI agent read your files, send emails, and call APIs without guardrails? Leash is the authorization and audit layer that sits between your agent and the outside world. You write simple YAML rules that say what's allowed. Everything else is denied. Every decision — allow or deny — is logged in a cryptographically signed, hash-chained audit trail that's tamper-evident by design.

One `pip install`, one policy file, and your agent is on a leash.

## 🌟 Highlights

- 🐕 **Deny by default** — nothing happens unless your policy says so
- 📜 **YAML rules** — human-readable, version-controllable, git-diffable
- 🔗 **Tamper-evident audit trail** — hash-chained and signed; deletions are detectable
- 👀 **Observe mode** — shadow new rules in production before enforcing
- 🔍 **Security scanner** — discover an MCP server's tools, classify risk, generate policies
- 🧩 **Framework-agnostic** — Python SDK, MCP proxy, or plain REST
- 🧠 **[OpenClaw ready](docs/docs/openclaw-guide.md)** — built-in policies for the popular open-source AI assistant
- ⚡ **One dependency** — `pip install leash`. No Go, no Rust, no sidecar containers
- 📖 **[Full documentation](docs/docs/index.md)** — getting started, policy writing guide, SDK reference, CLI reference, architecture

## ⬇️ Installation

```bash
pip install leash
```

Or run from source:

```bash
git clone https://github.com/chadeckles/leash.git && cd leash
make quickstart    # installs deps, starts server, runs a demo
```

Requires Python 3.11+ (macOS ships with 3.9 — run `brew install python@3.12` first if needed).

> 💡 **Running from source?** Use `pip install -e .` to make the `leash` command available globally, or use `./leash` directly from the repo root. See the [getting started guide](docs/docs/getting-started.md) for details.

### Starting the Server

After installing, start the server:

```bash
leash start              # start on port 8000
leash start --reload     # auto-reload for development
leash start --port 9000  # custom port
```

Or from source: `make dev`

## 🚀 Usage

### Python SDK

For developers building agents in Python (LangChain, CrewAI, or custom code). Add a few lines to your existing agent code — no separate config file needed — and every tool call is authorized and audited.

Wrap individual functions with a decorator:

```python
from sdk import LeashAgent

agent = LeashAgent("http://localhost:8000", name="my-agent")

@agent.tool("email.read")
def read_inbox(mailbox: str):
    return gmail.read(mailbox)

with agent:
    read_inbox("user@example.com")   # Leash checks permission first
```

The `name` is how policies find your agent — a policy with `agents: ["*email*"]` matches any agent with "email" in its name.

Or wrap many tools at once with `guard()` — no need to decorate every function individually:

```python
# Wrap a list of existing callables in one line:
guarded = agent.guard([read_inbox, send_email, summarize, search])

# Works with LangChain tools too:
guarded = agent.guard(langchain_tools)
```

If the action is denied, the function doesn't run. If Leash is unreachable, it denies by default (fail-closed).

> 💡 **Deny by default.** These examples will be denied until you [write a policy](#-writing-rules) that allows the action. That's the point — nothing runs unless your rules say so.

### MCP Proxy (Claude Desktop, Cursor, etc.)

[MCP (Model Context Protocol)](https://modelcontextprotocol.io) is how AI tools like Claude Desktop and Cursor connect to external tool servers — but MCP has no built-in authorization. This proxy sits between the AI and the MCP server so every tool call is checked against your policies, with zero code changes to the server:

```bash
python -m sdk.mcp_proxy \
    --agent-name "fs-agent" \
    -- npx -y @modelcontextprotocol/server-filesystem /data
```

Every `tools/call` is authorized, logged, and checked for tool poisoning automatically. The proxy auto-discovers the server's tools on startup.

See the [MCP Proxy Guide](docs/docs/mcp-proxy-guide.md) for Claude Desktop config, Cursor setup, and policy examples.

### OpenClaw

[OpenClaw](https://github.com/openclaw/openclaw) is a popular open-source personal AI assistant. It can run shell commands, browse the web, and manage files — all of which Leash can govern. Leash ships with a built-in OpenClaw policy:

```bash
# Register your OpenClaw agent
leash agents register --name "openclaw-agent" --vendor openclaw

# The built-in policy allows reads and web search, denies exec and browser.
# Customize app/policies/openclaw.yaml to match your needs.
```

See the full [OpenClaw Integration Guide](docs/docs/openclaw-guide.md) for setup, example policies, and tool mappings.

### REST API

Any language — register once, check permission before each action:

```bash
# Register an agent (returns agent_id + JWT token)
curl -s -X POST http://localhost:8000/agents \
  -H "Content-Type: application/json" \
  -d '{"name": "my-agent"}'

# Authorize an action (use the token and agent_id from above)
curl -s -X POST http://localhost:8000/authorize \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "'$AGENT_ID'", "action": "email.read"}'
```

Full interactive API docs at **http://localhost:8000/docs** once the server is running.

## 📜 Writing Rules

Rules live in `app/policies/*.yaml`. The server picks up changes automatically — no restart needed.

```yaml
name: email-agent
priority: 10
agents: ["*email*"]
rules:
  - action: "email.read"
    effect: allow
    reason: "Agent may read emails"

  - action: "email.*"
    effect: deny
    reason: "Everything else is blocked"
```

**How evaluation works:**

- **`priority`** — higher number = evaluated first. The built-in `default.yaml` is priority 0 (catch-all deny). Your policies should be 10+ to take precedence.
- **`agents`** — wildcard patterns matched against the agent's name. `"*email*"` matches any agent with "email" in its name.
- **Rules** — evaluated top-to-bottom within a policy. First match wins. No match anywhere = **denied**.

**Don't guess at rules — observe first.** Deploy new policies in `mode: observe` to see what *would* be denied without actually blocking anything. Once you're confident, flip to `mode: enforce`. See [Write Your First Policy](docs/docs/write-your-first-policy.md) for the full scan-first workflow.

Rules also support rate limiting, ABAC conditions, and OWASP threat tags — see the [policy writing guide](docs/docs/write-your-first-policy.md).

## 🔍 CLI Cheat Sheet

```bash
leash status                              # server health
leash agents list                         # registered agents
leash agents register --name "my-bot"     # register a new agent
leash policy validate app/policies/       # lint your YAML rules
leash audit scan                          # security scan (integrity, storms, shadows)
leash scan -- npx -y @mcp/server-fs /data # scan an MCP server's tools
leash dashboard                           # live terminal TUI
leash doctor                              # health-check your deployment
```

## 🐳 Docker

```bash
make docker-up     # build + start on port 8000
make docker-down   # stop + remove volumes
```

Images are published to [GHCR](https://ghcr.io/chadeckles/leash), multi-arch (amd64 + arm64), and signed with [cosign](https://github.com/sigstore/cosign).

## 🏗️ Project Layout

```
app/
  policies/       ← your rules (edit these)
  policy/         ← policy engine
  audit/          ← hash-chained audit log
  identity/       ← agent registration & JWT
  core/           ← config, auth, crypto, DB
sdk/
  client.py       ← Python SDK (LeashAgent)
  cli.py          ← CLI
  mcp_proxy.py    ← MCP authorization proxy
  scanner.py      ← security surface scanner
  dashboard.py    ← terminal TUI
tests/            ← test suite
```

## ✍️ Author

Built by [Chad Eckles](https://github.com/chadeckles).

## 💭 Feedback & Contributing

Found a bug? Have an idea? [Open an issue](https://github.com/chadeckles/leash/issues) or check out the [contributing guide](CONTRIBUTING.md).

## 📄 License

Apache 2.0 — see [LICENSE](LICENSE).
