This is the file format OneLLM reads and writes for agent definitions, scripted flows and deciders. It is YAML 1.2. The format is versioned as a whole; this is version 1. OneLLM reads every key described here and keeps every key it does not know.
Rules that apply to every file
- Unknown keys are kept. A key this document does not describe is loaded into the type's
ExtensionDataand written back with the same value. This holds at every level: the definition, a tool reference, a hook entry, a message, a message part, a tool call, a decider question. - A key with a null value and an absent key mean the same. OneLLM does not write keys whose value is null.
- A list that was written as an empty list stays an empty list when the file is saved again; an absent list stays absent.
- Saving something that was not changed returns the loaded text byte for byte, comments included. Once a value is changed the file is written again from the model: the same keys and values, with unknown keys kept, but not the comments or the original layout.
- Loading never grants a capability.
referencesname tool sources the agent would like; the runtime's grants decide. - Errors carry a position. A malformed file, a value of the wrong type, or a refused reference fails with the file name and
the 1-based line and column of the node (
BadDefinitionException). - Strict is the default. Strict loading fails on an ungranted reference, an invalid
missingKeyor a hook without afile. Lenient loading drops the offending entry and records the reason in the definition'sWarnings.
Agent definition (agent.yaml, *.flow)
A mapping. Every key is optional.
| Key | Type | Meaning |
|---|---|---|
name | string | Display name. |
description | string | One line. |
model | string | A catalog model name or alias, or provider:model. |
serviceTier | string | Service tier to request (flex, priority, ...). |
thinking | mapping | effort (string) and/or budget (integer): request-side reasoning controls. |
temperature | number | Sampling temperature. |
maxIterations | integer | The most model turns one run may take. |
maxTokens | integer | The most output tokens per turn. |
systemPrompt | string | A template. Rendered when a run starts and again each turn. |
references | list | Tool sources, below. |
workingDirectory | string | A template. |
initialPrompts | list | Messages that open every run, below. |
inputs | mapping | Default input values. Run inputs are merged over them. |
headers | mapping of string to string | Extra HTTP headers for HTTP tool sources; values are templates. |
invocationMode | string | interactive, delegated or autonomous. |
llmTurnLogs | boolean | Keep raw request and response logs for each turn. |
missingKey | string | default or error. What a template does with a key it cannot find. default renders <no value>. Agents and scripted runs default to default; deciders are always error. |
hooks | list | Hook files, below. |
references
Each entry is a mapping with one of:
routine: a tool source path or URI, with optionaltools(list of tool names; absent means all of them, an empty list means none) andrequired(boolean);swarm: a group of sources to take every tool from.
Other keys are kept. An entry that names a source the runtime has not granted is refused (strict) or dropped (lenient).
initialPrompts
A list of messages in the message format (spec/messages.md): user and assistant lists of parts, and toolCalls. Two keys
matter only here:
when(on a message or on a tool call): a template. The message or call runs unless the rendered text, trimmed and lower-cased, is empty,false,0,nooroff.- tool calls without a
resultare run before the first turn; ones with aresultare injected as they are.
A user part may be from: <path> to expand a list from the template data (for example inputs.images) into several parts.
Messages in initialPrompts usually have no id; the runtime gives them one when they enter an instance.
contextStrategy
Optional. Keeps a long run inside the model's window. contextStrategy: {type, triggerTokens | triggerPercent, keepLast} or just the
type name. It runs at a turn boundary, when the previous model call's context (input plus output tokens) reached the trigger
(triggerTokens, or triggerPercent of the model's window, default 70):
clearToolResults: the results of all but the latestkeepLast(default 3) tool-calling turns are replaced by the note[tool result cleared to save context]. Every call keeps a result, so no call is orphaned, and messages before the first change are untouched, so a provider's cached prefix stays valid up to there. Doing it again changes nothing.compact: messages before a user message at leastkeepLast(default 6) messages from the end are summarized by a model call and replaced by one user message that starts with[Summary of the earlier conversation]. The summarizer is the shippedcompactflow, replaceable on theRuntime; it runs as an instance of its own below this one, so its cost is in the subtree.providerNative: the provider compacts the conversation, when it can. A provider that cannot is skipped with a warning.
Each run adds an entry to compactions (spec/instances.md). A host hook can veto one.
hooks
A list of mappings: file (required, relative to the definition) and points (list of hook point names; absent means every
point the file handles). Host hooks registered on the runtime wrap these.
Flows (*.flow, flow.yaml)
A .flow file has the shape of an agent definition and is run in the scripted mode by default: the initialPrompts run in
order, one model call per user prompt, no tools. references in a flow are ignored with a warning.
flow.yaml beside it is metadata: name, description, version and any other keys (version history, input examples, rubrics).
OneLLM keeps the whole file and does not interpret the other keys; they are available as FlowMetadata.Other.
Decider (decider.yaml)
A mapping with:
| Key | Type | Meaning |
|---|---|---|
model | string | Required. The engine or model to ask. A catalog model of kind decision is a decisions engine; any other model answers as a chat model. |
state | any | A template tree rendered with the run's inputs. It is what the questions are about. |
questions | mapping | Required, at least one. Question id to question. Ids are 1 to 64 characters of letters, digits, _, -, .. |
llm | mapping | Optional. For chat-model engines only: samples (1 to 100, default 1), temperature (0 to 2), thinking (an effort name, or {effort, budget}), serviceTier. |
cache | mapping | Optional. key (1 to 64 characters; default the decider's name) partitions prompt-cache reuse; explicit: true marks the end of the state as the cached prefix. Engines that cannot cache ignore it. |
Other top-level keys are kept as extension data and written back unchanged.
A question is a mapping with:
type:choice,scoreornoul(a yes/no judgment with a probability);instructions: required; a template string, or a mapping of named parts, each a template;criteria: forchoice, a mapping from value to description with 2 to 255 entries; forscore, the levels from lowest to highest as a list (or a mapping from label to description) with 2 to 10 entries; fornoul, optional conditions (trueandfalsekeys that say what counts as yes and as no);forEach: exactly one{{ ... }}action that gives a list. The question is asked once per element, with.itemand.indexin scope. Its answer is a list in element order; an empty list asks nothing.
Templates in a decider
Every string that contains {{ is a template. Missing names are always errors (missingKey: error), embed is not available, and
code regions are not escaped. A string that is exactly one action, such as "{{ .inputs.customer }}", is a whole-value template: the
action's value is placed in the JSON as structured data (an object stays an object, nothing becomes null). Any other string is
rendered as text.
Request encoding
Structured values are written as compact JSON in the form Go's encoding/json produces, because engines and caches see the bytes:
object keys sorted, <, > and & written as \u003c, \u003e and \u0026, U+2028 and U+2029 escaped, and numbers read as 64-bit
floats and printed in their shortest form (plain decimal between 1e-6 and 1e21, exponent form outside).
Runs and answers
A run is an instance named after the decider. Its state is stopped when answered and error otherwise; the extension key decider
holds the engine, the origin (api, agent, playground, replay, eval; the last two kinds stay out of statistics), the models,
the calls with their cost and the answers.
Answers, by question id (a repeated question gives a list), each with type:
| Type | Fields |
|---|---|
choice | choice (the winning key), confidence (0 to 1), probabilities (key to probability) |
score | score (the expected level, 0 for the lowest), confidence, probabilities (level to probability), legend |
noul | noul (the probability of yes) |
Logic is optional and separate from the file: prepare turns the caller's inputs into the template inputs, decide turns the answers
into the outputs. A decider with no logic returns its answers as its outputs. A decider.schema.json beside the definition may describe the
inputs (inputs, with inputsDeclared); the keywords type, properties, required, additionalProperties, items, enum,
const, minimum, maximum and anyOf are enforced before anything is sent, and all others are ignored.