Templating
Polytoken renders facet and subagent bodies as templates, along with skill bodies when you opt in. You write custom definitions with the same template syntax as the shipped definitions.
Building a dependable harness on top of a coding agent is work I have done before; ed3d-plugins is my earlier effort at it. Polytoken ships that dependable baseline as the default. When you do need the harness to behave a certain way, you extend it in the same templates Polytoken ships. To decide which file your instructions need, see Where Instructions Live.
Frontmatter
Section titled “Frontmatter”Every file you author opens with a YAML frontmatter block, the same convention
other tools use. Frontmatter has two layers. The conventional keys, such as
name and description, sit at the top level where any harness reads them, so
they carry across tools. Anything specific to Polytoken lives under one key,
polytoken: the model a facet runs on, the tools a subagent gets, a skill’s
tags. The key’s value can also be just true, which claims the file for
Polytoken without setting any options. Carrying the key in either form is what
turns templating on for a skill; facets and subagents render as templates
whether or not the key is present.
Which keys are legal, both at the top level and under polytoken, depends on the
file type. The Template Reference lists them.
AGENTS.md files work a little differently; see
Project Context.
Templating with MiniJinja
Section titled “Templating with MiniJinja”The body of a facet or subagent definition, everything below the frontmatter,
is a template. A skill body becomes a template when its frontmatter carries
the polytoken key. Polytoken renders the body with
MiniJinja, which follows Jinja2’s
syntax closely. The everyday constructs, including
variables, conditionals, loops, and filters, are Jinja2-compatible. The
MiniJinja documentation covers the details and the
few advanced features it leaves out.
Polytoken renders the body before the model sees it, so your instructions can adapt. A facet can tell a vision model one thing and a text-only model another:
{% if supports_vision %}You can read images the user shares. Inspect them directly.{% else %}You cannot see images. Ask the user to describe what they show.{% endif %}Everything a template can read, every variable and the functions Polytoken adds, is in the Template Reference.
Templates catch typos at render time. Referencing a variable that does not exist raises an error rather than rendering blank, so a broken prompt never reaches the model.
Task prompts render before definition bodies
Section titled “Task prompts render before definition bodies”Polytoken first renders the task prompt passed to a subagent, then renders the
definition body with the rendered task available as prompt. In a counted
batch (several copies requested with the count input to the subagent
tool), Polytoken performs both renders for each clone, using that clone’s
launch metadata. When a task prompt must contain literal {{ ... }} or
{% ... %} text, wrap that text in a raw block:
{% raw %}Review the literal expression {{ not_a_variable }}.{% endraw %}Normal task text can use template
variables such as {{ model_group.name }} and {{ subagent_batch.ordinal }}.
The definition body can reference the rendered task with {{ prompt }}. Polytoken
keeps the rendered task and definition text as launch metadata, so a later
provider failover or configuration reload never re-renders the original
launch text.
Polytoken’s template functions
Section titled “Polytoken’s template functions”Polytoken adds functions to MiniJinja that query the current setup.
has_tool, has_skill, and has_mcp check availability for the current turn.
To check the model family, use is_model_variant; to retrieve a tool’s details,
use get_tool. is_web_search_available and is_decision_agent_available
report whether an integration is configured — configuration presence only, so
they stay true even when the integration fails at runtime, and a /reload
that changes integrations is reflected on the next composition. They answer
truthfully in facet, subagent, and skill templates; AGENTS.md renders always
see false. These functions let templates include instructions only when
the relevant tool or skill is available. See the
Template Reference for the full list and signatures.
Where templating applies
Section titled “Where templating applies”Polytoken always renders facet and subagent bodies as templates. A skill’s
frontmatter must carry a polytoken key to enable templating. Skill templates
use a smaller context: the skill list and project variables are present,
while the model, tool, and MCP server values are empty. In a skill template,
has_tool and has_mcp return false, and transclude() is unavailable.
By default, Polytoken treats AGENTS.md files as literal text. See Project Context for their templating opt-in.
Model identity
Section titled “Model identity”The shipped facet and subagent templates print one identity line right after the working directory:
Model: `{{ model_name }}` (provider: `{{ model_provider }}`, model ID: `{{ model_id }}`)The line is always present in the shipped templates, with no gating on model family or interactivity. It is composed fresh for every request, so the identity always names the model that attempt actually uses: after an explicit switch, a facet-pinned switch, or a routed failover, the next request names the new model. In a subagent, the identity names the subagent’s own model, never the parent conversation’s model.
The three values mean different things. model_name is the configured
selection name, model_provider is the configured provider, and model_id is
the upstream model identifier the provider itself uses. Custom facets that
replace the shipped templates choose their own composition, so the identity
line appears only where a template includes it.
Including other files
Section titled “Including other files”Facet and subagent bodies support load-time @file expansion and render-time
transclude() calls. Skill bodies loaded from disk support @file expansion
at load time.
Polytoken resolves @file references when loading a definition, before Jinja
directives run. Each @path/to/file reference becomes a block containing the
source path and the file’s text. Within that block, Polytoken escapes
ampersands and angle brackets and truncates very large files with a note
marking the cutoff. The inclusion preserves text literally, so {{ }} and
{% %} markers pass through unchanged rather than running as template code.
Use @file to share static text across definitions without templating.
The @ must appear at the start of the text or after whitespace, so email
addresses and typed references such as @skill: never count. Polytoken skips
references inside inline code, fenced code blocks, and Jinja regions. Quote
paths containing spaces: @"my notes.md". File paths resolve relative to the
definition file’s directory; Polytoken confines file access to that directory
subtree. An unsatisfied reference, such as a missing file or a directory,
remains literal text instead of failing the definition. The load-time scan
never searches included text for further references.
At render time, transclude("path.md") reads another file and Polytoken
renders its body with the current template context. For example,
{{ facet_name }} expands inside a transcluded file. Polytoken strips valid
YAML frontmatter before rendering, so a definition file contributes its
instructions without its metadata. A leading --- block that does not parse
as YAML remains part of the body. File paths resolve relative to the directory
of the file containing the transclude() call. Polytoken confines access to
that directory subtree and rejects ../ escapes.
transclude() also accepts polytoken:// addresses for shipped prompt
fragments. A transclude() Polytoken cannot satisfy, such as a missing file, a
directory, or a circular chain of includes, makes the render fail; no literal
text stays behind. Relative paths work only when the calling file lives on
disk: a shipped fragment has no directory of its own, so a relative
transclude() inside one fails the same way. See the
Template Reference for the full signature.