System prompts
In AEL, the Agent Engineering Language, you write an agent's business policy as a system prompt: inline, from a file, from the environment or from configuration. You can also run a model-driven node on its input alone, with no system prompt. Your code implements the operations and checks; the prompt guides the model's decisions about how to do the work.
Where a prompt comes from
A model-driven node names its system prompt in its settings:
# nodes/summarize.node.ael
node summarize(input: Request) -> Summary {
config {
prompt: file("prompts/summarize.md");
model: binding("primary_model");
}
return write_summary(input);
}
A prompt comes from one of four sources:
| Source | Where the text is | When the text is fixed |
|---|---|---|
| Inline | Written in the source file. | When you build. |
| File | A file in your project, such as prompts/summarize.md, packaged with the build. | When you build, or from a file mounted where the program runs, if you choose. |
| Environment | A named environment variable. | When a run starts, in the process that calls the model. |
| Configuration | A named configuration value or secret reference. | When a run starts, through your configuration. |
- A
file(…)path is relative to the project root, wherever the source file that names it sits: insrc/nodes/summarize.node.ael,file("prompts/summarize.md")namesprompts/summarize.mdat the root of the project, besidemain.ael. - A file source has to stay inside the project; a path that leads outside it is an error.
- An environment source reads only the variable you name. AEL never reads the environment as a whole.
- Keeping prompts in a
prompts/folder is a convention, not a rule.
The examples in this guide use the file source, file(…).
Ordered fallback
You can give one source, or several in the order you want them tried. At the start of a run, AEL takes the first source that has a usable prompt:
- If a file is missing, a variable is unset, a source is unavailable or its text is only white space, AEL moves on to the next source.
- A source that is present but wrong stops the run with an error, and never falls back: text that is not valid UTF-8, a template error, an unknown template variable or a path outside the project.
- Every fallback is recorded in your logs with the kind of source and the reason, never with the prompt's text or a secret value.
The order is always the one you wrote. No hidden precedence decides which prompt a run uses.
Running on input alone
If no source provides a system prompt, the node sends the model its input alone, with no system prompt: it runs "input-only". That is the default, and it is useful when the input already says everything the model needs.
| System prompt | Usable input | Outcome |
|---|---|---|
| Found | Yes | The model receives the prompt as instructions and the input separately. |
| None found | Yes | Input-only, unless you require a system prompt. |
| None found, and you require one | Yes or no | The run fails with a "system prompt unavailable" error. |
| Found, or none found and not required | No | The run fails with an "input missing" error. |
| Invalid | Either | The run fails with a prompt or configuration error. |
A missing or invalid model binding is a separate error: running input-only never removes the need for a model. A deterministic node has no prompt and no model binding, so none of this applies to it.
Instructions and input stay apart
- The system prompt goes to the model as instructions, and the run's input as ordinary input, each in its own channel.
- Input, tool results, retrieved documents and memory stay data. None of them is ever promoted to instructions.
- A prompt template can use only the variables you declare, filled from typed values. An undeclared variable is an error.
A skill brings instructions of its own: a skill is a versioned, reusable bundle of instructions, typed tools and functions that an agent or subagent loads through the skills it declares. Its instructions go to the model after the system prompt, marked with the skill they come from, and like every text they grant nothing; see Skills.
Building the model's input
An input builder, a helper function you write, turns a node's typed input into what the model receives. The result may be text, or other parts such as images, audio or files when the model accepts them; text is not required. Typed inputs and outputs describes input builders.
One prompt per run
- Each run resolves its prompt once, before any model call, and keeps it to the end.
- Changing a prompt file, an environment variable or a configuration value affects the runs that start afterwards, never a run already under way.
- Each run records which prompt it used, together with its model binding and configuration, so you can tell which version produced a result. The record identifies the prompt without storing its text in your logs.
- A caller can replace a run's prompt only if your deployment allows it and the caller is authorized.
Evaluations and prompt releases describes how to test a prompt change and promote it.
What a prompt cannot do
A system prompt, or any other text, cannot grant a permission, raise a limit or change who the caller is. A rule that must always hold, such as a limit on a payment amount, belongs in your code as well, as a typed check at the tool that makes the payment. See Effects and capabilities.
Keep secrets out of prompt files: they are packaged with your build. A value that must stay secret belongs in a configuration secret reference.