Manifests
Use this page to identify manifest kinds, shared metadata, validation, and editor support.
Every configuration file holds one or more manifests, separated by ---. The folder a file sits
in does not matter: the kind says what a manifest is. Files and folders whose name starts with
. or _ are skipped: a Kubernetes ConfigMap mounted as the folder loads each file once, and a
ticket input kept next to the manifests (_inputs/, _request.yaml) is never read as one.
apiVersion: afe.dev/v1alpha1
kind: Agent
metadata:
name: reviewer # required, unique per kind
labels: # optional, string → string
team: editorial
annotations: # optional; the description is one of them
afe.dev/description: Checks the text
spec:
model: cheap
systemPromptFile: prompts/reviewer.md # relative to this file
reads:
- text-request
- text
writes: review
Every manifest is a valid Kubernetes object, so the same files can later be applied to a cluster:
metadata.nameand node ids are DNS-1123 labels: lower-case letters, digits and-, starting and ending with a letter or digit, at most 63 characters (text-request, nottext_request);metadataholds onlyname,labelsandannotations, with Kubernetes keys and values;- the description is the annotation
afe.dev/description.
A prompt is either inline text (systemPrompt: |) or a file next to the manifest
(systemPromptFile), never both. On Kubernetes, where a custom resource has no files next to it,
use the inline form.
Keys inside spec are camelCase. Unknown keys are errors, except the parameters of plugin node
types.
Kinds
| Kind | What it declares |
|---|---|
Flow | A graph of nodes and edges, its input artifact, workspace and budget. |
Lane | A reusable, parameterised sub-flow, used by a lane or map node. |
Agent | An agent: harness, model, prompt, the artifacts it reads and writes, tools, budget. |
Schema | The fields of an artifact: string, int, number, bool, enum[a|b], list[…], object. |
Project | Where agents work: a folder or a git repository, sandbox and CI. The forge is none or github. |
Script | A custom command for a deterministic node; it runs in the project sandbox. |
Model | One model alias (metadata.name, for example cheap): provider, model, pricing, fallbacks. |
McpServer | An MCP server whose tools agents use as mcp:<server>.<tool>. |
AcpAgent | An external agent reached over ACP. |
Plugin | An out-of-process plugin the engine reaches over JSON-RPC 2.0 (stdio or HTTP). |
Runtime | The engine's own manifest: store, broker, tracer, work folder and sandbox. |
Secrets are never written in manifests: a manifest names the environment variable that holds
them (apiKeyEnv, tokenEnv).
An optional read ends with ? (- review?): the agent gets it only when it exists.
Durations are written as 30s, 15m, 4h or as seconds.
Editor support
The JSON Schema of every kind is generated from the engine's models. It is in the repository at
schemas/afe.dev-v1alpha1.json and on this site at
/schemas/afe.dev-v1alpha1.json.
With the YAML language server (VS Code, PyCharm, Neovim…), put this line at the top of a file:
# yaml-language-server: $schema=../schemas/afe.dev-v1alpha1.json
Validation
Loading a configuration reports every problem at once, each with its file, document and path:
flows.yaml#2: spec.edges[2]: a feedback edge needs `maxRounds`, or the flow could loop forever
agents.yaml#1: spec.model: unknown Model 'smart' (known: cheap)
Besides the structure, validation checks:
- references between manifests (agents, lanes, schemas, models, scripts, MCP servers, ACP agents);
- the graph: one start, every node reachable,
ENDreachable, no cycle withoutmaxRounds, a way to pick among several exits; - artifacts: every read has a writer upstream, reads after a
chooseare optional (name?), conditions cite existing artifacts, parallel branches never write the same artifact; - workspace and sandbox: a matching project exists, agents that run commands have a sandbox, git steps run on a git workspace.
Plugin node types and plugin harnesses produce a warning until plugins are loaded.