4
Commerce Planned
Agents discovering and paying each other for work. Once identity and spending enforcement are solid. A direction, not a scheduled milestone.
ROADMAP.md
Constle Architecture
Every layer runs in the host constle process. The agent gets a sandbox and a proxy. Nothing it can reach can switch a rule off.
01Layers
4
Agents discovering and paying each other for work. Once identity and spending enforcement are solid. A direction, not a scheduled milestone.
ROADMAP.md
3
A2A: Ed25519-signed envelopes, host-side sign and verify, declared peers only. The sandbox does no cryptography and never sees a peer's real endpoint. There is no discovery mechanism, by design.
internal/a2a/
2
did:key identity, the signed and hash-chained audit log, human gates at the MCP gate proxy, and the per-run / per-day USD ledger.
internal/identity · internal/audit · internal/mcpgate · internal/spending
1
A Firecracker microVM or a two-network Docker sandbox, no default route, and a Squid egress allowlist. The supervisor enforces duration and memory.
internal/sandbox/
02Chokepoints
Constle assumes nothing inside the sandbox is trustworthy. A control that relied on the agent reporting its own behaviour would only work when it wasn't needed.
| Chokepoint | When | Enforces |
|---|---|---|
| Sandbox environment construction | before the agent exists | credentials |
| Squid egress proxy | per run | sandbox.network.allowed_hosts |
| MCP gate proxy | per run | mcp.servers[].tools, human_gates.*, spending.* metering |
| A2A gate + host listener | per run | a2a.peers authorization, envelope signing and verification |
| Supervisor process | per run | limits.max_duration_seconds, sandbox.memory_mb |
The first row acts before the agent starts: the environment is composed, the sandbox is started with it, and there's no later moment to ask for more.
03Isolation
Each declared capability needs a minimum isolation level. A declared level may only strengthen that floor, never weaken it. Try it.
capabilities is notIt is not a sandbox permission system. Declaring read_file grants nothing and omitting it removes nothing; the image and mounts decide file access. Capabilities are self-asserted: an agent that omits external_transfer and declares isolation: none still runs at none. Capabilities naming irreversible actions are reported by validate as needing approval. That is advice; only human_gates.require_approval_for gates anything.
04Backends
Both render their proxy policy from the same function, so Docker and Firecracker enforce the same allowlist.
| Docker | Firecracker | |
|---|---|---|
| Boundary | Two-network container sandbox | microVM (hardware isolation) |
| Route out | Network created --internal; one on-link route, no default route | No ::/0 or global route; per-run nftables table drops the tap |
| IPv6 | Off, via explicit --ipv6=false | Kernel link-local fe80:: only |
| Selected when | Auto-detected, or --backend=docker | Auto-detected, --backend=firecracker, or required by isolation: kernel |
The generated Squid config is parsed by a real Squid in the test suite, and any complaint fails the build. Want another backend? gVisor is on the contributing wish list.
05Tool calls
It only knows CONSTLE_MCP_<ID>_URL, which points to the gate. The real server URL stays on the host.
Only POST, GET, DELETE. A body with duplicate or case-colliding keys is refused. Ambiguous paths and protocol upgrades are refused.
A tool not in mcp.servers[].tools is blocked at the gate.
If the tool name is in require_approval_for, the call waits for the terminal or a signed webhook decision.
Forwarded to the declared endpoint only. The response is metered against pricing; over the cap, the run is killed.
Each step lands in the signed, hash-chained audit log.
06Host-only
~/.constle/identities/<name>/The agent's private key, mode 0600.mcp.servers[].urlReal MCP endpoints. The agent sees only the gate.a2a.peers[].endpointReal peer endpoints. The agent can only name a peer.credentialsOnly the variables the Agentfile names, and nothing else from your shell.url_secret_refThe webhook URL lives in a host env var, not the Agentfile.~/.constle/webhook-keys/The approver's signing key from constle webhook-keygen. It goes to whoever runs the decision endpoint, never to the agent.