Docs Reference
The Agentfile
One declarative YAML file, enforced identically wherever the runtime is installed. It declares what the agent needs; the runtime makes the infrastructure decisions.
Transcript
0:00 Everything Constle enforces starts in one YAML file: the Agentfile. Identity gives the agent a did:key. With it, every audit entry is signed — and the run fails closed without the key. The sandbox gets its image, its memory, and allowed_hosts — the list that is the entire network policy. Tools come through declared MCP servers. Price them, and max_per_run_usd becomes a hard cap. human_gates names the exact tool calls that must wait for a person. on_timeout defaults to abort. Every field carries an honest label. Enforced: the runtime stops violations. Declared: parsed, but not enforced yet. egress and max_per_month_usd are declared, not enforced — and a cap with nothing to meter gets a loud warning.
0:54 One file, enforced the same wherever Constle runs.
Tip
constle init scaffolds a starter Agentfile (agent.yaml) with sane defaults. Start there instead of copying this example by hand.
An annotated exampleLink to this section
Every field the runtime actually consumes:
apiVersion: constle.dev/v1alpha1
kind: AgentManifest
identity:
name: invoice-processor
version: "1.0.0"
owner: [email protected]
did: did:key:z6Mk...4doK # from `constle identity create`; only the public DID lives here
sandbox:
image: invoice-processor:latest
isolation: kernel # or omit: inferred from capabilities
memory_mb: 512
network:
allowed_hosts: # this list IS the network policy
- api.groq.com
capabilities:
- external_api
- external_transfer
credentials: # the only host variables the sandbox receives
- name: GROQ_API_KEY
mcp:
servers:
- id: accounting
url: https://mcp.accounting.internal # host-side only; never enters the sandbox
tools: [list_invoices, pay_invoice]
pricing: # required for spending to be enforced
meters:
- usage_path: result.usage.input_tokens
usd_per_unit: "0.000003"
spending:
max_per_run_usd: "0.50"
max_per_day_usd: "5.00" # durable across runs; requires identity.did
limits:
max_duration_seconds: 300
human_gates:
enabled: true
require_approval_for:
- pay_invoice # must exactly match an MCP tool name (limitation 1)
approver_pubkey: did:key:z6Mk...Ap7w # from `constle webhook-keygen`; required when gating
notify:
- channel: webhook
url_secret_ref: HUMAN_GATE_WEBHOOK_URL
on_timeout: abort # the default: stop, never proceed
a2a:
listen: ":9443"
peers:
- name: auditor
did: did:key:z6Mk...9xQz
endpoint: https://auditor.internal:9443Why this differs from the README's example
The README's example gates pay_invoice without an approver_pubkey, and pkg/manifest/parser.go rejects that combination: human_gates.approver_pubkey is required when require_approval_for is non-empty. This one declares it, plus the notify webhook the decision is fetched from, and a credentials entry: an Agentfile with no credentials passes no host variables at all.
Enforcement labelsLink to this section
The field reference tags every field with one of four labels. The distinction between the middle two is the one that matters: a DECLARED field parses, validates and does nothing.
| Label | Meaning |
|---|---|
| E ENFORCED | The runtime actively prevents violations at execution time: it blocks the action or stops the run. |
| V VALIDATED | Checked for well-formedness and consistency at parse time; the manifest is rejected if it isn't. Not a constraint during execution. |
| D DECLARED | Parsed, defaulted and carried through (displayed, logged), but no code path changes behaviour based on it. |
| I INFORMATIONAL | Not read by the runtime at all. For humans and external tooling. |
If a field is DECLARED, you cannot rely on the runtime to stop the agent from violating it. Constle warns at validate and run wherever it can detect that a declared control won't be enforced.
The sections at a glanceLink to this section
| Section | What it controls | Enforced at |
|---|---|---|
identity |
Name, version, owner label and the did:key that signs the audit log |
run start (fails closed without the key) |
sandbox |
Image, command, memory, the isolation level | backend selection, supervisor |
sandbox.network |
allowed_hosts, the entire network policy |
Squid egress proxy |
capabilities |
Declared action classes; set the isolation floor | validation |
credentials |
The complete set of host variables the sandbox receives | sandbox environment construction |
mcp |
MCP servers, their tool allowlists and pricing | MCP gate proxy |
a2a |
Signed agent-to-agent peers | A2A gate and host listener |
spending |
Per-run and per-day USD caps | MCP gate (metering) |
limits |
max_duration_seconds |
supervisor |
human_gates |
Tool calls that wait for a human | MCP gate proxy |
compliance, metadata |
Descriptive fields | not enforced (declared or informational) |
Full referenceLink to this section
- Field reference: the AgentManifest specification, every section and field with its type, default, validation rules and enforcement label.
- Annotated example file:
spec/agent-manifest.yaml, kept executable.constle validatepasses on it. - Check an Agentfile without running anything:
constle validate agent.yaml.
Something wrong or unclear? Open an issue. The specifications on these pages are copies of spec/ in constle/constle.