recipe.yaml file, and the platform validates it at build time, derives typed input and output schemas from it, and executes it at run time.
This page describes every rule the platform applies: which fields are honored, how recipes are validated, how input and output schemas are constructed, and how the recipe and caller input combine at task start.
Recipe file
The agent version’s files must include arecipe.yaml at the root. The file must be valid YAML whose document root is a mapping. Other files may exist alongside recipe.yaml; the platform does not consume them. JSON recipes (recipe.json) are not supported.
Lifecycle
The samerecipe.yaml is parsed at two points:
- Build time — The recipe is fully validated. On success,
description,input_schema, andoutput_schemaare extracted and persisted on the agent version. Any validation error fails the build, and all errors are reported together. - Task start — The recipe is re-parsed from the version’s files.
instructions,prompt, andparametersare not persisted — the recipe file is their single source of truth. Because versions are immutable, a recipe that validated at build time parses identically at task start.
Recipe fields
Every top-level field is honored, ignored, or rejected.
At least one of
instructions or prompt must be present.
Validation
Recipe-level
descriptionis required and must be a non-empty string.instructions,prompt, andtitlemust be strings when present.- At least one of
instructionsorpromptmust be present. - Top-level fields not listed in the table above are rejected.
Parameter-level
parameters, when present, is a list of mappings. Each parameter must satisfy:
Default coercion: any YAML scalar
default is accepted and coerced to the declared type. Accepted values by type:
number— integer, float, or numeric string.boolean— YAML boolean or"true"/"false"(case-insensitive).date— ISOYYYY-MM-DDstring.select— must be one of the declaredoptions.string— any scalar, kept as a string.
Template-level
instructions and prompt are Jinja-style templates.
- Templates must parse without syntax errors.
- Every variable referenced in
instructionsorpromptmust be a declared parameter. - Every declared parameter must be referenced in
instructionsorprompt. (activitiesare ignored on Guild and do not count as usage.) - The built-in
{{ recipe_dir }}variable is rejected — there is no recipe directory in the Guild execution model. - Rendering is sandboxed: template expressions cannot access host internals.
Response-level
response, when present, must be a mapping containingjson_schema.response.json_schemamust be a mapping and a structurally valid JSON Schema (Draft 2020-12).responsewithoutjson_schemais a build error.
Input schema
The input schema persisted on the version is a JSON Schema (Draft 2020-12) describing this shape:type: object and additionalProperties: false. It always contains a text property. It contains a parameters property only when the recipe declares at least one parameter.
text
text is always present with type: string.
- Required when the recipe has no
prompt— the caller must supply the initial message. Description:"The message for the agent." - Optional when the recipe has a
prompt. Description:"Optional message appended after the recipe's default prompt."
Parameters
Theparameters property has type: object and additionalProperties: false. Its required array lists every parameter whose requirement is required or user_prompt.
user_prompt-requirement parameters are treated as required. Goose’s semantics (“interactively prompt the user if not provided”) have no headless equivalent — leaving them unset would surface literal {{ key }} text in the rendered prompt. On Guild, the input form is the user prompting.parameters itself is required at the top level when its required array is non-empty.
Each parameter maps to a JSON Schema property according to its input_type:
Each property carries the parameter’s
description. Optional parameters also carry their coerced default.
Example
prompt, required at the top level would be ["text", "parameters"].
Output schema
Whenresponse.json_schema is present, it is persisted verbatim as the version’s output schema.
When absent, the output schema defaults to the canonical text shape, so the agent’s final answer posts to chat:
Runtime semantics
At task start, the parsed recipe and the validated input combine as follows:- Parameter values — declared defaults overlaid with
input.parameters. - Rendering —
instructionsandpromptare rendered with the parameter values. - System prompt — the rendered
instructions, when present. - Initial message — determined by whether the recipe has a
promptand whether the caller suppliedtext:- Recipe has no
prompt→text(the schema makes it required). - Recipe has a
prompt, notextgiven → the rendered prompt. - Both present → the rendered prompt, then
text, joined by a blank line.
- Recipe has no
- Workspace context — when present, prepended to the rendered
promptat task start, wrapped in a{% raw %}block so it is not treated as a template. The resultingpromptorders workspace context first, then the rendered recipe prompt, thentext. It is never injected into the renderedinstructions. Prepending the context inside thepromptcarries it on every--resumeturn, matching the native Goose runtime behavior.
Chat input mediation
Chat-originated input arrives as canonical text{"type": "text", "text": "..."}. When the target schema has a top-level text string property, that input maps to {"text": "<text>"}. Validation then applies as usual — a bare chat message can only start a Goose agent whose schema does not require parameters.