Placeholders
A placeholder is a switch inside your prompt: one named slot, a few named blocks of instructions, and the caller picks which block goes there.
Placeholders let one prompt behave differently for different customers, roles or workflows without copying it. The instruction blocks live in Genum, are versioned with the prompt, and are tested like the rest of it. The caller only picks one by name.
Placeholders replace Context Memory. If you used memory keys, see Migrating from Memory.
How a Placeholder Works
Put {{key}} anywhere in the prompt text:
# Role
You are a support assistant for our online store.
{{tone}}
# Task
Answer the customer's question about their order.
Then define the placeholder in the prompt's Placeholders tab:
| Part | Example | Notes |
|---|---|---|
| Key | tone | Letters, digits and underscores, up to 64 characters. It is exactly what goes between {{ and }}. |
| Description | "How formal the answer is" | Optional note for authors. Never sent to the model. |
| Values | formal, friendly | Each value has a name and a content block, the text that replaces {{tone}}. The content may be empty. |
| Default | formal | Optional. At most one value per placeholder can be the default. |
A caller never sends the text of a block, only the name of a value. Everything the model reads stays in Genum, where it is committed and tested.
How the Value Is Chosen
At run time, Genum fills each {{key}} in the text as follows:
- It uses the value the caller selected by name.
- If nothing was selected, it uses the default value.
- If there is no default either, it replaces
{{key}}with nothing.
A few rules follow from this:
- Every occurrence of
{{key}}is replaced, not only the first. - Substitution is positional. A block is inserted only where its
{{key}}appears. If you remove{{tone}}from the text, selecting atonevalue has no effect. - A
{{key}}that no placeholder defines is left in the text as written, so the model sees the literal{{key}}. Genum flags it so you can define it. - A selection for a key that does not appear in the text, or naming a value that does not exist, is ignored and reported back to the caller. An unknown value name falls back to the default.
In the Playground
- The Placeholders tab lists the prompt's placeholders. Select one to see and edit its values, each with its own editor for the instruction block.
- Under the prompt editor, every placeholder found in the text is shown as a chip. Use it to choose the value the next Playground run uses.
Versioning
Placeholders are part of a prompt version. Committing a prompt saves its placeholders and their values together with the text. Productive runs, the default for API calls, use the committed placeholders, not the ones you are currently editing.
Editing an instruction block therefore reaches production only after you commit, exactly like editing the prompt text. The version history shows the placeholders each version was committed with.
Testing
A test case stores the value it uses for each placeholder and always runs with exactly those values, so every variant of a prompt can have its own regression tests. The test case table shows each test case's selection in the Placeholders column.
Test cases created from a log keep the placeholder values of that run.
Deleting a placeholder or one of its values removes that selection from the test cases that used it. The test cases themselves are kept.
Using Placeholders Through the API
Select values by name when you run a prompt:
{
"id": 123,
"question": "Where is my order?",
"placeholders": { "tone": "friendly" }
}
The response tells you what was applied:
"placeholders": {
"resolved": { "tone": "friendly" },
"ignored": []
}
resolvedmaps every key found in the text to the name of the value that was used, ornullif none was.ignoredlists the keys you sent that were not applied.
The API can also:
- Render a prompt, returning the final instruction with placeholders filled in, without running it.
- Create a prompt together with its placeholders and values.
Both are described in the Native API Integration guide.
Migrating from Memory
Context Memory has been replaced by placeholders, and existing memory keys were converted automatically:
- Every prompt that had memory keys now has a placeholder named
memory_key. Each former memory key is one of its values: the key became the value name, and the memory text became its content. - No value is marked as default, so a run that selects nothing adds nothing, as before.
- Test cases that used a memory key now use the matching
memory_keyvalue. - Memory was always appended at the end of the prompt. To keep that behaviour,
{{memory_key}}was added at the end of each affected prompt's draft, and the prompt was marked as uncommitted. You can move it anywhere in the text.
Committed versions were not changed. Until you commit the updated draft, productive runs of an affected prompt use its previous version, which contains no {{memory_key}}, so no memory block is added to them. Review the draft, run your tests and commit it to restore the memory behaviour in production.
The API still accepts memoryKey on a run. It is deprecated and equivalent to "placeholders": { "memory_key": "..." }. If a request sends both, placeholders.memory_key wins.
Integration Options
Placeholders can be used with Genum's integration options:
- Native API Integration: select values with
placeholders, render and create prompts - n8n Custom Nodes: select a value of the
memory_keyplaceholder with the node'smemoryKeyfield - OpenTelemetry: record which values your own agent used, so a replay uses the same ones