Facets
The Prompting and Input page covers using facets: switching between plan and execute, and what a facet changes. A facet is a persona that guides how the model executes your prompts and workflows. It lives in a Markdown file: the front matter declares what the facet does (its model, tools, skill access, color), and the body is the system-prompt framing the model works under.
Switching facets changes the system prompt and the available tools while keeping
the same conversation. That is how plan and execute work together. The model
researches and writes a plan in plan, then handoff_plan moves the work into
execute, which gives the model its edit and shell tools. The conversation built
up while planning carries over.
Where facets live
Section titled “Where facets live”A facet file goes in .polytoken/facets/ in your project, or in the facets/
directory of your global Polytoken config for facets you want everywhere. The
filename is the facet’s name: scribe.md defines a facet named scribe, and the
name key in the front matter must match the filename, or Polytoken rejects the
file.
Facets override by replacement, not by merge. When two facets share a name, the
more specific one wins: a project facet overrides a global one, and either
overrides a shipped facet such as plan or execute. A custom plan is your
plan, not an edited copy of the shipped one.
The body is a template
Section titled “The body is a template”The body below the front matter is a template, rendered as described in Templating. It becomes the system-prompt framing for the facet, and it is the entire framing. Polytoken does not add a base prompt of its own.
In most facets you will want Polytoken’s shipped base prompt under your own
framing. Include it with transclude at the top of the body:
{{ transclude("polytoken://system_prompts/facet.md") }}
Your job is to help the user with their documents.The shipped plan and execute facets both start this way, then add their own
lines. The shipped base prompt carries tool-use guidance and other behavior the
model depends on. Leaving the transclude out means writing that guidance
yourself.
A small facet
Section titled “A small facet”A facet named scribe, in .polytoken/facets/scribe.md, that gives the model
your whole Notion workspace and a documents-assistant framing:
---name: scribepolytoken: tools: [mcp__notion] color: "#7c3aed"---{{ transclude("polytoken://system_prompts/facet.md") }}
Your job is to help the user with their documents. You have full access to theirNotion workspace through its tools. Work from what the user asks for.mcp__notion grants every tool from the Notion MCP server. To grant the server
but hold back one tool, add a tools_deny:
tools: [mcp__notion] tools_deny: [mcp__notion__delete_page]Front-matter keys
Section titled “Front-matter keys”Conventional keys like name sit at the top level. Every Polytoken-specific key
is polytoken.<key>. The machine-readable schema is in the
Template Reference; the table below is the
meaning of each key.
| Key | Type | Default | Meaning |
|---|---|---|---|
name | string | required | The facet’s name. Must match the filename. |
polytoken.model | string | active model | Pins the facet to a model. Without it, the facet uses the active model. |
polytoken.fallback_models | list | none | Models to fall back to when the primary is unavailable. |
polytoken.tools | list | none | The tools the facet exposes. Accepts literal names, mcp__<server> for all of a server’s tools, tag!ALL for every tool, and tag!ALL_MCP for every MCP tool. |
polytoken.tools_deny | list | none | Tools to remove from the granted set. Literal names only, using the full mcp__<server>__<tool> name for an MCP tool. |
polytoken.undeferred_tools | list | none | The granted tools whose full definitions appear up front rather than through tool search. Literal names only. |
polytoken.skills_allow | list | allow all | The skills the facet permits, as names or tag!<name> groups. Leaving it out means no restriction, so every skill is allowed. |
polytoken.skills_deny | list | none | The skills the facet blocks. Deny wins over allow. |
polytoken.color | string | none | The facet’s accent color, as #RRGGBB. Sets both light and dark. |
polytoken.color_light | string | none | The accent color for light themes. Overrides color. |
polytoken.color_dark | string | none | The accent color for dark themes. Overrides color. |
polytoken.autonomous_hint | string | none | Guidance for the autonomous permissions classifier. When Autonomous mode evaluates a tool call in this facet, Polytoken adds this text to the classifier’s context to steer its allow, ask, and deny decisions. |
polytoken.facet_transitions.<target>.allowed | boolean | open | Whether this facet may switch to <target>. With no transitions declared, every switch is allowed. |
polytoken.facet_transitions.<target>.condition | string | none | When set, switching to <target> first asks you to confirm, showing this text. |
Tool and skill access notes
Section titled “Tool and skill access notes”switch_facet is a regular tool. List it in polytoken.tools to let a facet
switch to another facet. The shipped execute facet includes it; plan leaves
it out, so the model cannot leave planning on its own and uses handoff_plan to
transition the work to you.
Leaving polytoken.skills_allow out means no restriction, so the facet gets every
skill. Once you write a non-empty list, though, it is a commitment: if your
patterns match no skills, through a misspelled name or an empty tag! group,
Polytoken fails the facet’s skill access closed rather than reverting to allow-all.
A non-empty polytoken.skills_allow that matches nothing leaves the facet with no
skills.
The tag!ALL and tag!ALL_MCP shorthands belong in polytoken.tools. The
lowercase tag!<name> form is for skills only, in polytoken.skills_allow and
polytoken.skills_deny, and Polytoken rejects it in a tool list.
Loading changes
Section titled “Loading changes”Polytoken loads facets when it starts and when you reload its configuration. Editing a facet file does not take effect until then.