Templating & macros
Every prompt Marginalia sends is rendered from a template: the master template, the user prompt, lorebook entries and the summary prompt. Templates are Handlebars with SillyTavern-compatible macros on top. This page explains how that is implemented and how to add variables and macros. What users can write is documented in the user guide: Prompt templates and the Macro reference.
The texts of the agents are the exception: the system prompt, the compaction prompt and the instructions of an
agent (Defaults.DEFAULT_AGENT_PROMPT and the others around it) are plain text, put into the request as they are, with no
Handlebars and no macros.
The code is in domain/templates/ (data objects, context, variables), domain/templates/macros/ (translator,
helpers, macro registry) and domain/service/impl/TemplateServiceImpl.java.
Rendering in one picture
flowchart LR
T["template text<br/>(SillyTavern macros<br/>+ Handlebars)"] --> MT["MacroTranslator"]
MT --> HB["pure Handlebars source<br/>+ literal table"]
HB --> C["Handlebars.compileInline<br/>(cached)"]
C --> R["apply(Context)"]
D["TemplateData<br/>+ TemplateContext"] --> R
H["MacroHelpers<br/>st_* helpers"] --> R
R --> P["postProcess<br/>({{trim}})"]
P --> O["prompt text"]TemplateService.processTemplate(template, name, data):
-
Translate the SillyTavern syntax into plain Handlebars (
MacroTranslator.translate). -
Compile the result with Handlebars. Compiled templates are cached by template text (Caffeine, 500 entries, 24 h after last access), so a lorebook entry is parsed once, not on every generation.
-
Render it against a Handlebars
Contextbuilt from theTemplateData(MacroHelpers.createContext). -
Post-process the output:
{{trim}}markers are removed together with the newlines around them.
Handlebars runs with EscapingStrategy.NOOP - the output is a prompt, not HTML, so quotes, & and < stay as
they are.
isValidTemplate(template, name) only does steps 1-2, so it catches syntax errors. isValidTemplate(template, name, dataClass) also walks the compiled template (Template.collect of variables and sections, in all branches) and
reports names that would end in helperMissing (see ValidationResult.unknownNames(). They are warnings, isValid() stays true; the UI shows them as the field's helper
text (TemplateHints.showWarnings). Names relative to the current context (this, ., ../x, @index) and
parameters ({{#if name}}) are not checked.
Where templates are rendered
The order of the [generation pipeline]