> ## Documentation Index
> Fetch the complete documentation index at: https://docs.servflow.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Dynamic content

> How prompts and tool settings use the message that started the run: what double curly braces mean, and what they can read for each kind of entry

A prompt is mostly fixed text, with gaps that are filled in each time the agent runs: the question someone asked, the name of the person who wrote, what an earlier step found. The gaps are written in double curly braces, `{{ }}`. ServFlow calls this dynamic content. This page explains how to read and write it. For every function, see the [Dynamic content reference](https://docs.servflow.io/references/dynamic-content.md).

## Reading a template

Text with gaps in it is called a template. This one is the **User prompt** of a Discord agent:

```
Answer this question from {{ .discord.display_name }}:

{{ .discord.content }}
```

Everything outside the braces is sent as written. Each pair of braces is replaced when the agent runs: the first with the name of the person who wrote, the second with their message.

## Where you can use it

In a **System prompt** and a **User prompt**, in a tool's settings, in a step's settings, and in a guard's condition. A field that accepts dynamic content shows `Supports {{ }} templates` under its label.

## What you can read depends on how the agent was started

| The agent is started by | Read the message with | Example |
| - | - | - |
| A webhook | `body`, `param`, `header` | `{{ body "question" }}` |
| A Discord bot entry | `.discord` | `{{ .discord.content }}` |
| A Telegram bot entry | `.telegram` | `{{ .telegram.text }}` |
| A GitHub entry | `.github`, and `body` for the rest of what GitHub sent | `{{ .github.repo }}`, `{{ body "issue.title" }}` |
| A trigger, handed a task by another agent | `input` | `{{ input "instruction" }}` |

Three things to watch:

* A Discord agent cannot use `body`. It has no web request to read.
* `body` reads a web request only when the request is sent as JSON.
* An agent that runs on a schedule has no message to read, so leave `input` out of its prompts.

The [Available entry handlers](https://docs.servflow.io/references/entry-handlers.md) lists every name under `.discord`, `.telegram`, and `.github`.

## What you can read from any agent

* **What an earlier step found.** `{{ .customer.name }}` reads `name` from a step called `customer`. See [Steps before the agent](https://docs.servflow.io/concepts/entries.md#steps-before-the-agent).
* **A stored secret.** `{{ secret "weather-api-key" }}`. See [Secrets](https://docs.servflow.io/concepts/secrets.md).
* **Inside a tool, what the agent passed to it.** `{{ tool_param "question" }}`. See [Add a tool to an agent](https://docs.servflow.io/guides/add-a-tool.md).

## Small changes to a value

A function can change a value on its way in. Three common ones:

| To | Write |
| - | - |
| Turn a number into text | `{{ tostring (body "count") }}` |
| Join a list into one line | `{{ join .tags ", " }}` |
| Compare two values, in a guard | `{{ eq (body "plan") "pro" }}` |

The brackets in `(body "count")` mean "work this out first".

## If something is missing

A gap whose value is missing is left empty, and the prompt still goes out. Write prompts that read sensibly when that happens.

A misspelt function name is different. In a guard, ServFlow refuses it when you save. In a prompt, the agent fails when it runs.

## Dynamic content in the dashboard

Every field that accepts dynamic content has two small buttons. A short field keeps them in its corner; a prompt, or a field whose value has grown long, shows them in a row under the field. Typing inside braces suggests names as you go.

**Insert a variable** opens a menu of what the field can read, such as the results of steps and your secrets, and writes the braces for you.

**Open editor** opens the field in a larger window. A prompt opens as Markdown, with a preview beside the text that shows each pair of braces as a placeholder. A field that can hold other kinds of text has a **Text**, **Markdown**, and **HTML** switch; it only changes how the text is shown, and what is saved is what you typed. In a tool's fields, the window also offers **Tags**: one for each input the model sends the tool, which writes `{{ tool_param "..." }}` for you. **Done** closes the window.

![The Insert a variable menu open on a prompt, listing the results of two steps](https://mintcdn.com/servflow/545ICsSSJFr63lId/images/concepts/dynamic-content/01-insert-variable.png?fit=max\&auto=format\&n=545ICsSSJFr63lId\&q=85\&s=6f2bc1fad6dae099986be96c0feafb56)

![The open editor showing a User prompt that reads two steps and the request body, with its preview beside it](https://mintcdn.com/servflow/545ICsSSJFr63lId/images/concepts/dynamic-content/02-expand-editor.png?fit=max\&auto=format\&n=545ICsSSJFr63lId\&q=85\&s=420c515f1883de15b5a0c67e6088488d)

## Related

> [card] [Dynamic content reference](https://docs.servflow.io/references/dynamic-content.md)
>
> Every function, with what it takes and returns.

> [card] [Available entry handlers](https://docs.servflow.io/references/entry-handlers.md)
>
> Every name a Discord, Telegram, or GitHub entry provides.

> [card] [Guard rails](https://docs.servflow.io/concepts/guard-rails.md)
>
> Conditions that decide whether a tool may run.

> [card] [Entries and entry handlers](https://docs.servflow.io/concepts/entries.md#steps-before-the-agent)
>
> The steps an entry runs, whose results a prompt can read.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.