Metadata-Version: 2.4
Name: canopy-runtime
Version: 0.1.2
Summary: Canopy Agent Safety Runtime: policy enforcement for tool-using agents
Author: Canopy
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: http
Requires-Dist: requests>=2.25; extra == "http"
Provides-Extra: gateway
Requires-Dist: fastapi>=0.100; extra == "gateway"
Requires-Dist: pydantic>=2; extra == "gateway"
Requires-Dist: uvicorn[standard]>=0.23; extra == "gateway"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: httpx>=0.24; extra == "dev"
Requires-Dist: requests>=2.25; extra == "dev"
Requires-Dist: fastapi>=0.100; extra == "dev"
Requires-Dist: pydantic>=2; extra == "dev"
Requires-Dist: uvicorn[standard]>=0.23; extra == "dev"
Dynamic: license-file

# Canopy Runtime

Minimal **Agent Safety Runtime** focused on a single primitive:

`authorize_action(agent_ctx, action_type, action_payload)` → `{decision, reason, avid}`

Decisions:
- `ALLOW`
- `DENY`
- `REQUIRE_APPROVAL`

Every decision is appended to a JSONL **hash-chain audit log** (`audit.log` by default).

## Quickstart
```bash
pip install canopy-runtime
```
```python
from canopy import authorize_action

decision = authorize_action(
    agent_ctx={"env": "production"},
    action_type="execute_shell",
    action_payload={"command": "rm -rf /tmp/logs"},
)
print(decision["decision"])  # DENY
print(decision["reason"])    # Denied by policy: matched /rm\s+-rf/
print(decision["avid"])      # AVID-...
```

An `audit.log` file is created automatically in the current directory.

## Default policy pack

Works out of the box — no configuration required:

- `execute_shell`: denies destructive patterns; requires approval for network/install commands.
- `modify_file`: denies protected paths; requires approval unless path is in `agent_ctx["safe_paths"]`.
- `call_external_api`: requires approval.

## Config

| Variable | Default | Description |
|---|---|---|
| `CANOPY_POLICY_FILE` | bundled `default.yaml` | Path to a custom YAML policy file |
| `CANOPY_AUDIT_LOG_PATH` | `audit.log` | Path to audit log |

Pass `agent_ctx["safe_paths"]` as a list to allowlist paths for `modify_file`:
```python
agent_ctx = {"env": "production", "safe_paths": ["/tmp/", "/repo/"]}
```

## Optional HTTP gateway
```bash
pip install canopy-runtime[gateway]
CANOPY_AUDIT_LOG_PATH=/tmp/canopy_audit.log python -m uvicorn canopy.service:app --port 8010
```

## Demo CLI
```bash
canopy-demo
canopy-demo --safe-path /tmp/
```

## Development
```bash
git clone https://github.com/Mavericksantander/Canopy
cd Canopy
pip install -e ".[dev]"
pytest -q
```

## License

MIT
