Agentfile in 5 minutes
An Agentfile is one YAML file that says what an agent may reach, call, spend and receive. Constle reads it once, when the run starts, and enforces it from outside the agent.
On this page
- What you'll get
- 1. Scaffold a file
- 2. Name the agent and its image
- 3. Write the network policy
- 4. Declare what crosses from your shell
- 5. Set the isolation floor
- 6. Bound the run
- 7. Validate, and read every warning
- Mistakes that look like controls
- Where to go next
- FAQ
- Is the Agentfile read again while the agent runs?
- Does a field I leave out default to something permissive?
- Can I validate an Agentfile in CI without the keys?
Source release coming soon
The source and installers are not public yet, so there is nothing to install today. This guide documents Constle as it behaves now. More in Project status.
What you'll getLink to this section
- A minimal Agentfile that validates, for an agent that calls one model API.
- The sections most agents need, and the part of the runtime that enforces each one.
- The mistakes that make a control look real when it isn't, and what
constle validatesays about each.
The policy is data, not code: there is no rule language, and every field the runtime reads is listed in the Field reference with one of four labels, ENFORCED, VALIDATED, DECLARED or INFORMATIONAL. A DECLARED field parses and changes nothing. More in The Agentfile.
1. Scaffold a fileLink to this section
constle init writes agent.yaml in the current directory, with a comment on every field. The file it writes passes constle validate as it stands, so you start from something valid and change it.
constle init
constle validate agent.yamlKeys are checked strictly: a key the schema does not define is an error, not a silent no-op, and the message names the keys that section accepts and the nearest match. A typo such as capabilties fails validation instead of quietly turning a control off.
2. Name the agent and its imageLink to this section
identity:
name: report-writer # lowercase letters, digits, hyphens; names the audit log
version: "1.0.0"
sandbox:
image: report-writer:1.0.0 # pin a digest or an immutable tag
memory_mb: 512 # the default; exceeding it kills the workloadThe agent is an ordinary container image. sandbox.command overrides the image's own command, in exec form (a list of arguments, no shell interpolation). The audit log is named after identity.name, in ~/.constle/logs/<name>-<YYYY-MM-DD>.jsonl.
3. Write the network policyLink to this section
sandbox:
network:
allowed_hosts:
- api.groq.com # the only host on the internet this agent can reachallowed_hosts is the entire network policy. An empty or absent list reaches no host at all; only Constle's own MCP and A2A gates stay reachable. Entries are plain lowercase hostnames, with one optional leading . to include subdomains. A scheme, port, path or wildcard is rejected at validate time.
sandbox.network.egress parses and is ignored (limitation 5). How the proxy enforces the list, and what it refuses besides undeclared names: Stop an AI agent exfiltrating data.
4. Declare what crosses from your shellLink to this section
credentials:
- name: GROQ_API_KEY # the value stays in your shell; only the name is here
- name: AGENT_TASK # non-secret input crosses the same wayThis list is complete and exclusive for host environment variables: the sandbox receives these and no other variable from your environment. Declare nothing and the agent receives nothing. secret_ref reads the value from a differently named host variable, so two agents can both see GROQ_API_KEY with different values. Names that Constle sets itself (anything starting CONSTLE_, and the proxy variables) are refused.
Declared values do enter the sandbox, as environment variables the agent can read. That is the price of not intercepting the agent's TLS (What Constle is not).
5. Set the isolation floorLink to this section
capabilities:
- external_api # outbound API calls: network isolation at leastcapabilities is a list of action classes, and its one enforced job is the isolation floor: read_file and write_file need process, web_search, external_api and send_email need network, and spawn_subagent, external_transfer and delete_records need kernel (a Firecracker microVM). Leave sandbox.isolation out and the runtime uses the floor; write it and it may only be stronger. It is not a permission system: nothing is blocked at run time because it is missing from this list. Backends and levels: Architecture.
6. Bound the runLink to this section
limits:
max_duration_seconds: 300 # the supervisor kills the agent at five minutesThe timer runs in the host process, not in the agent. When it fires, the run is stopped and the audit log records terminated_by_limit. Omitted or 0 means no limit.
7. Validate, and read every warningLink to this section
constle validate agent.yamlValidation runs nothing. It prints the isolation level it resolved (and whether it was declared or inferred), and it warns about each control that is declared but will not be enforced. The whole file so far:
apiVersion: constle.dev/v1alpha1
kind: AgentManifest
identity:
name: report-writer
version: "1.0.0"
sandbox:
image: report-writer:1.0.0
memory_mb: 512
network:
allowed_hosts:
- api.groq.com
capabilities:
- external_api
credentials:
- name: GROQ_API_KEY
- name: AGENT_TASK
limits:
max_duration_seconds: 300On a machine where GROQ_API_KEY and AGENT_TASK are not exported, validate warns that they are unavailable and constle run refuses to start until they are. The quickstart shows that output for an agent very like this one.
Mistakes that look like controlsLink to this section
| You wrote | What actually happens | What validate and run do |
|---|---|---|
egress: none |
Parsed and ignored; allowed_hosts decides |
Nothing: it is limitation 5 |
require_approval_for without enabled: true |
Nothing is gated | Warn: human_gates.enabled is false — NO gate is enforced |
| A gate entry that provably matches no tool of a declared MCP server | That entry gates nothing | Warn, naming the entries that run without approval |
max_per_run_usd with no priced MCP server |
Nothing is metered, so nothing is capped | Warn: spending limits are declared but NOT enforced |
max_per_month_usd |
Parsed, never enforced | Warn: spending.max_per_month_usd is NOT enforced. |
max_per_run_usd: "0" |
Rejected as ambiguous | Validation error: omit the field to leave a cap unset |
isolation: network beside external_transfer |
Weaker than the floor | Validation error naming the capability |
identity.did with no key on this machine |
No signing key | validate warns; run refuses to start |
Where to go nextLink to this section
- Sandbox an AI coding agent puts this file to work on a real agent image.
- Lock down MCP servers and Require human approval for MCP tool calls add the
mcpandhuman_gatessections. - Give each AI agent a verifiable identity adds
identity.did, which signs the audit log. - Every field, with its type, default and label: the Field reference.
FAQLink to this section
Is the Agentfile read again while the agent runs?Link to this section
No. The runtime reads it once, before the sandbox starts, and nothing inside the sandbox can change it. To change the policy, stop the run, edit the file and start a new run.
Does a field I leave out default to something permissive?Link to this section
The network defaults to nothing: no allowed_hosts means no host. No credentials means no host variables. Human gates default to off, spending caps to unset and max_duration_seconds to no limit, so write the ones you want.
Can I validate an Agentfile in CI without the keys?Link to this section
Yes. constle validate warns about credentials and identities that are not available on the machine, and does not fail on them, because validation is not execution. constle run is where they are required.