The agent.acl manifest file, its syntax, and how build-time and runtime values work.
An agent is declared in an agent.acl file. The manifest describes everything the compiler needs to
know: which archetype to target, which graph drives the agent, which model providers are available,
how the agent identifies itself, what tools it can use, and how it is served. The compiler reads
this file and produces an artifact from it.
The format is HCL (HashiCorp Configuration Language) with a small set of extensions specific to agentc. If you have written Terraform or any other HCL-based tool, the syntax will feel familiar. If not, it is straightforward to pick up from the examples.
A manifest is a collection of named blocks at the top level. The order of blocks does not matter.
build {
archetype = "standalone"
}
locals {
version = "1.0.0"
}
provider "anthropic" {
kind = "anthropic"
models = ["claude-haiku-4-5"]
config {
api_key = secret(runtime("ANTHROPIC_API_KEY"))
}
}
agent "my_agent" {
graph {
type = "react"
}
version = locals.version
prompt = "You are a helpful assistant."
model {
provider = "anthropic"
name = "claude-haiku-4-5"
}
}Each top-level block serves a distinct purpose. See the manifest reference for the full field documentation of each block.
Most fields in the manifest accept either a constant value or a runtime() expression. This
distinction controls when the value is resolved.
Constants are baked into the artifact at compile time. They never change after the build.
port = 8080Runtime values are resolved from environment variables when the binary starts. If the variable is not set, the default is used instead.
port = runtime("HTTP_PORT", 8080)The first argument to runtime() is the name of the environment variable. The second argument is the
default. The default is optional for values that are required at startup.
This lets you build one artifact and deploy it in multiple environments by changing environment variables, without recompiling.
The secret() wrapper marks a runtime value as sensitive. It behaves identically to runtime() at
startup, but the value is redacted in logs and in the output of agentc inspect.
api_key = secret(runtime("ANTHROPIC_API_KEY"))Use secret() for API keys, tokens, passwords, or any value you do not want to appear in diagnostic
output.
The locals block defines named constants that are resolved at build time. They are useful for values
that appear in multiple places in the manifest.
locals {
version = "1.0.0"
region = "us-east-1"
}
agent "my_agent" {
graph {
type = "react"
}
version = locals.version
}Locals are referenced with locals.name syntax. A local can provide a constant string or a runtime() default string for build-time interpolation. See locals for the constraints.
String values in the manifest support ${...} interpolation. This substitutes local values when the manifest is resolved.
locals {
version = "1.0.0"
}
agent "my_agent" {
graph {
type = "react"
}
description = "My agent, version ${locals.version}."
}The prompt field additionally supports Jinja2 template syntax for dynamic rendering at runtime. See
Write templated prompts for details.
Structural fields that define the shape of the build, such as archetype, the agent graph type,
and kind on tool and provider blocks, are always build-time. The compiler needs these values
during code generation and they cannot vary at runtime.
Most configurable fields accept runtime(). These include hosts, ports, API keys, feature flags,
model names, and similar values. The manifest reference notes which fields are build-time only.
Some fields are runtime values even when omitted. Each is bound to a fixed environment variable and uses its default when that variable is unset, so a deployment can adjust it without the manifest naming it. Writing the field in the manifest replaces the binding. The reference page of each block lists these variables.
build block chooses your deployment target.© 2026 pogue.dev. All rights reserved.
CC BY 4.0