Working Draft — agentrc 0.1.0-draft.6 is an evolving specification draft, not a finished standard. Expect breaking changes. Changelog →
View Markdown

Agentfile Core Profile

Version: 0.1.0-draft.6 — Working Draft
Status: Working Draft (# syntax=agentrc.agentfile/v0.1)
Date: 2026-06-30
Audience: compiler / frontend authors (the agentrc BuildKit frontend and the agentrc / arc CLI)

The normative keywords MUST, MUST NOT, SHOULD, and MAY follow RFC 2119. This profile is the compile-side companion to the specification; where the two disagree, the spec wins.

Purpose

The Core Profile defines what it means to read a Dockerfile-shaped Agentfile and compile it into an OCI artifact — namely, the ai.agentrc.* image labels plus the layers that carry the agent’s /mnt tree. It is the contract a compiler implementation claims: recognize the four agentrc keywords (IDENTITY, CAPABILITY, SOP, POLICY) and the standard Dockerfile keywords, and emit the labels and layers exactly as the spec’s translation tables require.

This profile covers build, not run time. What a platform does with the labels (grant / narrow / reject, enforce via Cedar, project /mnt) is the Platform Conformance Profile and the Enforcement (Cedar) Profile; how the labels and package are shaped is the OCI Labels & Package Profile.

A small core is deliberate. The Agentfile adds only four keywords to a model developers already know; everything else is a standard Dockerfile keyword. Keeping the new surface tiny is what lets two independent compilers — the BuildKit frontend and the native CLI — produce byte-for-byte identical artifacts.

Keyword summary

There are four new keywords. Everything else is a standard Dockerfile keyword, used as-is or with a documented extension. A conformant compiler MUST recognize all of these.

Keyword Origin Role in agentrc
IDENTITY New Who / what the agent is: name, version, author, description.
CAPABILITY New What modalities / patterns the agent supports (text, streaming, multimodal, …).
SOP New The agent’s system prompt / objective / standard operating procedure.
POLICY New Typed, namespaced request for a resource, model, or operational constraint.
FROM Dockerfile Base image and agent inheritance (FROM another-agent).
CMD Dockerfile The agent’s invocation surface — the framework / loop to run.
COPY Dockerfile Add local tools, skills, MCP bundles, or an SOP file into the /mnt tree.
ADD Dockerfile (extended) Add remote resources via --remote plus delivery flags.
HEALTHCHECK Dockerfile Liveness probe; MAY invoke a projected tool.
LABEL Dockerfile Standard OCI metadata; available for hand-authored ai.agentrc.* metadata.
ENV / ARG / WORKDIR / USER / EXPOSE / RUN Dockerfile Standard semantics; available, unchanged.

There is no TOOL, MCP, SERVER, FUNC, CRED, SECRET, AUDIT, MOUNT, MEMORY, or RATELIMIT keyword. Tools / skills / MCP are added with COPY / ADD; memory / context / model / CPU are POLICY requests; audit rides on agent.hooks.*; secrets are deferred. Any earlier draft that recognized those keywords is stale and MUST NOT be revived by this profile.

The /mnt projection layout

The destination path under /mnt is what tells the compiler what a resource is. There is no per-type keyword; a file copied to /mnt/tools/x is a tool, one copied to /mnt/mcp/x is an MCP bundle, and so on. The compiler MUST use this layout:

/mnt
├── tools/     # each tool is an executable; argv in, structured output out
├── skills/    # skill bundles (a directory of instructions/scripts/resources)
├── mcp/       # MCP server bundles or configs
├── proc/      # runtime-populated (live policy, identity, budgets, audit tail)
└── SOP        # the agent's system prompt, as a readable file

/mnt/proc is populated at run time by the platform, not by the compiler. See the /mnt Projection Profile for the full layout.

Required behavior

An implementation claiming this profile MUST:

  1. read a text file named Agentfile or an explicitly supplied path (-f Agentfile);
  2. ignore blank lines and comments (#), while honouring the # syntax=agentrc.agentfile/v0.1 parser directive on the first line;
  3. parse the four agentrc keywords and the standard Dockerfile keywords listed above, case-sensitively;
  4. capture an SOP <<EOF … EOF heredoc verbatim, without interpreting its inner lines as Agentfile instructions, and embed it as the readable file /mnt/SOP;
  5. accept the inline and file-backed SOP forms and embed each at /mnt/SOP, emitting a pointer + digest label — never the full prompt text;
  6. honour the ADD --remote delivery flags — --cached (default) / --runtime and --fail-if-unavailable (default) / --warn-if-unavailable, plus standard --chmod / --chown — fetching --cached resources at build and recording --runtime resources as references;
  7. use the destination path under /mnt to classify each COPY / ADD resource as a tool, skill, MCP bundle, or SOP;
  8. translate authored intent into ai.agentrc.* labels and /mnt layers exactly per the spec §9 tables (reproduced below);
  9. auto-derive an explicit, attributed network egress label from any URL in agent.hooks.* or agent.interrupt_endpoint, never a silent egress;
  10. report line numbers for parse failures, and reject unknown agentrc keywords rather than silently dropping them.

A POLICY line is authored in short form (no ai.agentrc. prefix); the compiler prepends the namespace when it emits the label. The compiler never evaluates a POLICY — it only records the request. Whether a request is granted, narrowed, or rejected is a platform decision.

Unknown substrate.<token>.* keys parse; foreign platform keys are ignored. A platform-scoped request substrate.<token>.* (spec §8.7) is a KEY under the existing substrate.* namespace, not a new namespace. The compiler MUST accept any platform token — including tokens it does not recognize — and emit the corresponding ai.agentrc.substrate.<token>.* label verbatim; an unknown token is NEVER a parse error (a linter MAY warn). At enforcement time a platform simply ignores keys scoped to a different platform. The compiler does not judge which tokens are “real”; it records the request and lets the platform pick the keys scoped to itself.

Build translation (compile targets)

These are the tables the compiler MUST implement. They are reproduced from the specification so the compile-side contract is self-contained.

POLICY → labels

Each POLICY <key> <value> becomes ai.agentrc.<key>=<value>.

Authored Emitted label
POLICY agent.idle_timeout 5m ai.agentrc.agent.idle_timeout=5m
POLICY agent.context.type autocompressed ai.agentrc.agent.context.type=autocompressed
POLICY agent.hooks.pre https://hooks.internal/pre-step ai.agentrc.agent.hooks.pre=https://hooks.internal/pre-step (+ auto-derived egress)
POLICY agent.sub_agents.max 5 ai.agentrc.agent.sub_agents.max=5
POLICY substrate.runtime.memory 8gb ai.agentrc.substrate.runtime.memory=8gb
POLICY substrate.ptty true ai.agentrc.substrate.ptty=true
POLICY model.name claude-opus-4 ai.agentrc.model.name=claude-opus-4
POLICY model.capability vision ai.agentrc.model.capability.vision=true
POLICY network dns:api.github.com:443 ai.agentrc.network.dns.api.github.com=443

For an auto-derived egress, the compiler MUST emit both the egress label and its attribution, so it is never a silent network hole:

ai.agentrc.network.dns.hooks.internal=443
ai.agentrc.network.dns.hooks.internal.source=auto:agent.hooks.pre

IDENTITY / CAPABILITY / SOP → labels

Authored Emitted label(s)
IDENTITY name=claims-triage version=1.0 ai.agentrc.identity.name=claims-triage, ai.agentrc.identity.version=1.0
CAPABILITY streaming ai.agentrc.capability.streaming=true
SOP … / COPY ./sop.md /mnt/SOP ai.agentrc.sop=/mnt/SOP, ai.agentrc.sop.sha256=<digest> (pointer + digest, never full text)

Resource delivery → layers + labels

Authored Build behaviour Emitted label(s)
COPY ./tools/x /mnt/tools/x Embed file as a layer. ai.agentrc.tool.x=local
ADD --remote --cached <url> /mnt/tools/x Fetch at build, embed as a layer. ai.agentrc.tool.x=<digest> + ai.agentrc.tool.x.origin=<url>
ADD --remote --runtime <url> /mnt/mcp/x Do not embed; record reference. ai.agentrc.mcp.x=runtime:<url>

For every embedded MCP server or skill, the compiler MUST emit both the resolved digest and the origin reference, so a platform can re-point to a mirror at deploy time without rebuilding:

ai.agentrc.mcp.github=sha256:abc123...
ai.agentrc.mcp.github.origin=https://registry.agentrc.io/mcp/github:latest

Policy encoding

The compiled request set MUST be retrievable in either form, and the build MAY support both, selected by --policy-mode:

Which form is the default for arc build is open decision #1 — the --policy-mode inline|digest flag is the seam.

Identical output from both front doors

agentrc has two build paths — the BuildKit frontend invoked by the # syntax=agentrc.agentfile/v0.1 directive, and the native agentrc / arc CLI (see the CLI page). They are two front doors to the same compiler.

A conformant implementation MUST produce identical OCI artifacts — same layers, same ai.agentrc.* labels, same digest — from the same Agentfile, whether built via the frontend or via arc build. This is the single most important conformance property of this profile and is exercised adversarially by the conformance suite (build-labels-identical).

Worked translation

A minimal Agentfile:

# syntax=agentrc.agentfile/v0.1
FROM python:3.11-slim
IDENTITY name=claims-triage version=1.0 author=acme
CAPABILITY text
CAPABILITY streaming
SOP You are a claims-triage specialist. Escalate anything ambiguous to a human.
CMD claude --print
COPY --chmod=755 ./tools/file_read /mnt/tools/file_read
POLICY model.name        claude-opus-4
POLICY network           dns:api.github.com:443

compiles to layers carrying /mnt/tools/file_read and /mnt/SOP, plus these labels in the image config:

ai.agentrc.identity.name=claims-triage
ai.agentrc.identity.version=1.0
ai.agentrc.identity.author=acme
ai.agentrc.capability.text=true
ai.agentrc.capability.streaming=true
ai.agentrc.sop=/mnt/SOP
ai.agentrc.sop.sha256=<digest>
ai.agentrc.tool.file_read=local
ai.agentrc.model.name=claude-opus-4
ai.agentrc.network.dns.api.github.com=443

The platform reads those labels — never the Agentfile source.

Validation recommendations

A compiler / linter SHOULD warn when:

  1. IDENTITY name= is missing in an artifact intended for publication;
  2. FROM uses a mutable tag such as latest;
  3. an ADD --remote uses --runtime without a clear failure mode, so the default --fail-if-unavailable is recorded explicitly;
  4. a COPY / ADD targets a path outside /mnt for a resource that is meant to be projected (it will not be classified as a tool / skill / mcp);
  5. a removed keyword (TOOL, MCP, CRED, MOUNT, RATELIMIT, …) is encountered — it is stale and MUST be rejected, with a pointer to the COPY / ADD / LABEL / POLICY replacement.

Compatibility note

The reference compiler — the BuildKit frontend and the arc CLI — is in progress. This profile defines the target compile semantics; an implementation SHOULD publish a support matrix rather than implying it emits every label in the tables above. Do not advertise a profile you do not pass.