Constle¶
Constle is a runtime that enforces what an AI agent is allowed to do — network, spend, approvals, identity — from outside the agent, so a compromised agent cannot turn the rules off.
Constle runs an AI agent inside a sandbox with no default route, allowlists every packet it sends, meters what it spends, pauses sensitive calls for a human, and signs the audit log. None of that runs in the agent's process — so there is nothing in there for a prompt injection to switch off.
Three of the four layers are shipped. The quickstart builds the CLI and runs a real agent under enforcement in about a minute; the architecture explains what each layer is doing while it runs.
Enforcement, demonstrated¶
You declare the policy in one YAML file. Constle runs the agent inside a sandbox with no default route, routes every packet through an allowlisting proxy, meters cost at the tool-call boundary, pauses sensitive calls for a human, and writes a signed, hash-chained audit log. None of that lives in the agent's process, so there is nothing in it for a prompt injection to disable.
An agent whose manifest declares allowed_hosts: [api.groq.com], reaching for one declared host and one undeclared one:
┌─ agent output ──────────────────────────
│ https://api.groq.com/ CONNECT allowed TLS tunnel opened, server replied
│ https://evil.example.com/ CONNECT refused Tunnel connection failed: 403 Forbidden
└─────────────────────────────────────────
$ grep network ~/.constle/logs/egress-probe-2026-08-08.jsonl
{"event":"network_allowed","details":{"bytes":5314,"host":"api.groq.com","http_status":200,"method":"CONNECT"}}
{"event":"network_blocked","details":{"bytes":3404,"host":"evil.example.com","http_status":403,"method":"CONNECT"}}
The second request never left the sandbox. The agent didn't get a refusal from the model — it got no route at all: the proxy declined to open the tunnel, which is the 403 on that line and the only thing that 403 means here. The 200 in the log is the tunnel being established for the declared host, not the answer Groq eventually gave; whatever status the real server returns after that is between the agent and the server, and Constle doesn't read it (see limitation 3).
Both attempts are in the audit log either way — the blocked one is how you find out it happened.
What Constle enforces¶
The same nine rows as text, with the caveats spelled out
The diagram above is a summary. This is the table it summarises — longer, and the version to search, copy, or read with a screen reader.
| Capability | Mechanism | Status |
|---|---|---|
| Sandboxed execution | Firecracker microVM (hardware isolation) or a two-network Docker sandbox with no default gateway. Auto-detected, or forced with --backend=docker\|firecracker. isolation: kernel selects Firecracker and warns loudly if it has to fall back to Docker. |
Shipped |
| Network egress | All egress traverses a Squid proxy allowlisting network.allowed_hosts. Matching is name-based (dstdomain), and a separate rule denies destinations given as raw IPs — including the real IP of an allowed host — so resolving a name yourself and connecting to the address is not a way around the allowlist. Every allow and every block is an audit event. |
Shipped |
| Max duration | The agent is killed when limits.max_duration_seconds elapses; the kill is recorded as terminated_by_limit. |
Shipped |
| Audit log | JSONL per agent per UTC day. With identity.did set, every entry is Ed25519-signed and hash-chained; constle audit verify detects tampering and reports the offending line. |
Shipped |
| Spending limits | Hard max_per_run_usd and max_per_day_usd. Metered at the MCP gate against each server's declared pricing. The daily ledger is durable across runs, keyed by DID so a rename can't reset it. A priced server whose response omits a declared usage value kills the run — a server that could omit its usage field could zero its own bill. Scope caveats: limitations 2 and 3. |
Shipped |
| Human gates | Declared MCP servers are reachable only through a protocol-aware gate proxy. A matching tools/call pauses for a terminal approval; on_timeout defaults to abort. Non-interactive stdin (CI, piped input, backgrounded runs) is detected up front and announced, rather than blocking on a read that never resolves — the call then waits out its deadline and on_timeout decides. Matching caveat: limitation 1. |
Shipped |
| Cryptographic identity | W3C did:key (Ed25519). The private key stays at ~/.constle/identities/<name>/ (mode 0600) and never enters the sandbox. constle run fails closed on a declared DID with no local key. |
Shipped |
| Agent-to-agent messaging | Signed envelopes to explicitly declared peers only. The host signs and verifies; the sandbox does no cryptography and never sees a peer's real endpoint. No discovery mechanism exists, by design. Replay caveat: limitation 4. | Shipped |
| Agent commerce | — | Not built |
Constle is not a framework. It doesn't decide how an agent reasons or plans. LangGraph, CrewAI, or hand-rolled code run inside it unchanged.
What Constle is not¶
Not an agent framework. It governs the environment, not the logic.
Not a cloud provider. It installs on your infrastructure, any cloud or on-premise. Software, not servers.
Not a monitoring overlay. Isolation stops exfiltration even if the model is fully compromised, because enforcement sits below the agent rather than inside it. There is nothing for a compromised agent to disable.
Not finished. See Known limitations — they are listed there rather than discovered later.
Not a closed platform. Apache 2.0, and the Agentfile format is an open, independently auditable standard.
Before you rely on any of this¶
The gaps are documented, not hidden
Spending is metered only at the MCP gate, max_per_month_usd parses but
does nothing, and sandbox.network.egress has no consumer at all.
The full list is short and worth the two minutes.