constle docs constle docs pre-1.0

Quickstart

On Linux with Docker, from the CLI to a signed, verified audit log of a sandboxed run.

On this page

Source release coming soon

The source, the installers and signed releases are not public yet, so there is nothing to install today. The steps below document Constle as it behaves now, with its real output, and show what the first minute looks like once they are published.

1. Install the CLILink to this section

Not available yet: the installers and the source are published together. Until then, constle.dev/install and /install.ps1 only print that Constle is not available for install, and exit with an error, so a piped install installs nothing.

2. Check the example manifestLink to this section

Nothing runs yet:

shell
./constle validate examples/basic-agent/agent.yaml
Output
✓ examples/basic-agent/agent.yaml is valid

  name:        basic-agent
  version:     0.1.0
  isolation:   network (inferred from capabilities)
  image:       basic-agent:latest
  memory:      512MB
  allowed:     api.groq.com
  credentials: GROQ_API_KEY, AGENT_TASK

⚠️  warning: spending limits are declared but NOT enforced:
   no mcp.servers entry declares a pricing block, so there is nothing to meter.
   cost is measured only at the MCP gate proxy (constle does not TLS-intercept
   generic allowed_hosts traffic); declare pricing on the MCP servers that cost money.

⚠️  warning: some declared credentials are not available on this machine:
   GROQ_API_KEY (not set on the host), AGENT_TASK (not set on the host)
   `constle run` will refuse to start until each one resolves —
   export the variable, or point credentials[].secret_ref at the one that holds it

The spending warning is the design working

A declared cap with nothing metering it gets called out loudly instead of quietly looking real. See Spend caps and metering and Known limitations. The credentials warning goes away once you export the two variables in step 4.

3. Create the agent's identityLink to this section

shell
./constle identity create basic-agent [email protected]

Paste the printed did:key:... into the manifest under identity.did. The name matters: the key is looked up by the Agentfile's identity.name, and the audit log is named after it.

4. Build the example image and run itLink to this section

shell
docker build -t basic-agent:latest examples/basic-agent
export GROQ_API_KEY=gsk_...            # free key: https://console.groq.com
export AGENT_TASK="What is 2+2?"
./constle run examples/basic-agent/agent.yaml

There is no

--env flag An agent receives exactly the host variables its manifest declares under credentials: (the example declares GROQ_API_KEY and AGENT_TASK) and nothing else from your environment crosses into the sandbox. Only the variable name goes in the manifest; the value stays in your shell and is never written into the image, the manifest or the audit log. Declare nothing and the agent gets nothing.

5. Verify the audit logLink to this section

shell
./constle audit verify ~/.constle/logs/basic-agent-$(date -u +%F).jsonl
Output
⚠️  signatures are valid under the log's own key, which was not pinned: /home/you/.constle/logs/basic-agent-2026-08-08.jsonl

  entries:   2 (every signature valid under that key, hash chain intact)
  signed by: did:key:z6MkgroKowQYDZjDmqbn82mJv4YFPKowS2xDhxGYrp4u3P1o
  not pinned: a log re-signed with any key also passes this check; pin the
              key with --did=<did:key:…> or with --agentfile=<path> (an
              Agentfile that declares identity.did)

Edit a single byte of that file and run it again:

Output
error: TAMPERING DETECTED in /home/you/.constle/logs/basic-agent-2026-08-08.jsonl
  line 1: invalid_signature — signature does not verify against did:key:z6MkgroKowQYDZjDmqbn82mJv4YFPKowS2xDhxGYrp4u3P1o — the entry was edited after signing

Pin the key with --agentfile=examples/basic-agent/agent.yaml (or --did=) and a clean log reports ✓ audit log verified. With identity.did set, constle run also fails closed: if the manifest names a DID with no matching private key on this machine, the run refuses to start rather than proceeding under an identity it cannot prove. More in Audit log and verification.

6. Gate a tool callLink to this section

Pause a named MCP tool call until a human decides. The example agent declares no MCP server, so this step needs an Agentfile with an mcp.servers entry that exposes the tool: a gate entry that matches no declared tool gates nothing, and validate says so. First create an approver key. It is not an agent identity: it authenticates the human approving, not the agent making the call.

shell
./constle webhook-keygen approver
Output
✓ webhook signing key created: "approver"

  did:       did:key:z6Mk…
  key file:  /home/you/.constle/webhook-keys/approver (mode 0600 — never leaves this machine)

  this key is NOT an agent identity — it authenticates the human
  approving gated calls, not the agent making them.

  give the private key file to whoever operates the decision
  endpoint, and paste the DID into your Agentfile:

    human_gates:
      approver_pubkey: did:key:z6Mk…

Then declare the gate in the Agentfile:

agent.yamlyaml
human_gates:
  enabled: true
  require_approval_for:
    - pay_invoice                 # the exact MCP tool name
  approver_pubkey: did:key:z6Mk…  # required when require_approval_for is set
  notify:
    - channel: webhook
      url_secret_ref: HUMAN_GATE_WEBHOOK_URL
  on_timeout: abort               # the default: refuse the call, stop the run

At run time the call waits for whichever answers first: the terminal prompt, or a signed decision from your endpoint. Human gates covers the prompt, the webhook protocol and how decisions are verified.

Where to go nextLink to this section