Yes Templates
unlistedby pianox2
User-friendly Obsidian templates and snippets.
Yes Templates
Yes Templates is an Obsidian plugin for creating notes and inserting content from declarative templates. Templates support prompted variables, suggestion lists, date tokens, formula composition, note-template inheritance, and snippet composition, all expressed in one function notation with no scripting required.
There are two template types: note templates that create new notes, and snippets that inject content into existing notes. Five commands cover the core workflow: creating notes, inserting snippets, creating linked notes, scaffolding new templates, and validating template syntax.
Preview status
Version 0.2.0 is a manual-install preview distributed through GitHub Releases.
It is not distributed through Obsidian Community Plugins and is not published to npm. Use GitHub Issues to report bugs or describe workflows that are hard to express with the current template language.
Design goals
- Keep templates readable as notes, not programs.
- Make common template tasks work without scripting.
- Use one consistent function style for dynamic values.
- Make prompts and suggestions explicit and predictable.
- Reuse structure through note inheritance and snippets.
Installation
Install Yes Templates by copying the release assets into your vault.
- Download
main.js,manifest.json, andstyles.csswhen present from the0.2.0GitHub release assets. - Create this folder in your vault:
.obsidian/plugins/yes-templates/ - Copy the downloaded files into that folder.
- Reload Obsidian.
- Enable Yes Templates in Settings > Community plugins.
Keep the three assets from the same release together. Do not mix files from different releases or from source checkout builds.
Getting started
- Open Settings > Yes Templates and set the Templates folder to any subfolder in your vault (e.g.,
templates). - Run the Create template command from the command palette. Choose
noteas the type and enter a name likemeeting-note. The new template file opens with a skeleton config block. - Edit the template — add frontmatter, fill in the config block, and write the body. See Template grammar below for the complete syntax reference.
- Run Create note from template from the command palette. Pick your template. Answer any prompts. The new note is created and opened.
Any template file you save inside your templates folder is immediately available in the pickers — no reload required.
What Yes Templates supports today
- Note templates that create new notes with configurable output folders, filenames, frontmatter, and body content.
- Snippets that insert reusable content into the active note and can merge frontmatter into that note.
- Prompted text, fixed suggestions, file suggestions, property suggestions, date/time values, cursor selection, formulas, slots, and fills.
- Note-template inheritance through
extends, with parent placement controlled by{{slot(content)}}. - Snippet composition through
{{snippet(name)}}and block snippet calls. - Live indexing of the configured templates folder, so changed templates appear without reloading Obsidian.
Commands
Create note from template
Opens a fuzzy picker listing all note templates. Pick a template, answer any prompts, and the plugin creates a new note and opens it (subject to the open behavior setting). The output path and filename can be configured per template or fall back to the settings defaults.
Use this when you want a new standalone note from a template.
Insert snippet
Opens a picker listing all snippets. Pick a snippet, answer any prompts, and the plugin inserts the resolved content at the cursor — or replaces the current selection. Snippet frontmatter is merged into the target note's frontmatter automatically.
Use this when you want to inject reusable content into an existing note.
Create linked note from template
Like "Create note from template", but also inserts a wikilink to the new note at the cursor in the source note. If you have text selected, the selection becomes the link alias and is replaced by the link.
Use this when you want to create a note and reference it in the note you are currently editing — for example, to extract a paragraph into its own note.
Create template
Prompts for a type (note or snippet) and a filename, then creates a new template file in your templates folder with a skeleton config block. Opens the file immediately so you can start editing.
Use this to scaffold a new template rather than creating a blank file manually.
Validate template
Runs a complete parse-time check on the active editor's content and shows a modal with any errors, warnings, and (if applicable) the inheritance lineage. Works on any open markdown file — including files outside the templates folder, which are validated as hypothetical templates.
Use this when authoring or debugging a template to catch syntax errors, unresolvable references, formula cycles, or type mismatches before using the template.
Template grammar
A template file is a standard Obsidian markdown file with up to three parts: output frontmatter, a config block, and a body.
File structure
---
tags: [meeting]
date: "{{date('YYYY-MM-DD')}}"
---
```yaml:yes-templates
type: note
output: meetings/
filename: "{{date('YYYY-MM-DD')}}-{{formulas.title}}"
formulas:
title: "{{prompt('Meeting title')}}"
```
# {{formulas.title}}
**Attendees**: {{suggest_files("people/", label="Attendees")}}
## Notes
{{prompt("Notes")}}
Output frontmatter (between --- fences): standard YAML. For note templates, copied into the created note. For snippets, merged into the target note's frontmatter. Variable references inside frontmatter values are resolved like any other reference.
Config block (the ```yaml:yes-templates fence): plugin configuration. Stripped from all output — never appears in created or injected content. Must use the exact info string yaml:yes-templates.
Body: everything else. Becomes the new note's content (note templates) or the injected content (snippets).
Config block keys
| Key | Type | Purpose |
|---|---|---|
type | note or snippet | Template type. If omitted, the type is inferred from the folder name (notes/ or snippets/ subfolder) or defaults to note. |
output | string (vault-relative path) | Output folder for created notes. Example: projects/active/. |
filename | string | Filename pattern for created notes. May include variable references. Example: "{{date('YYYY-MM-DD')}}-{{formulas.title}}". |
extends | string (path relative to templates root) | Inherit from a parent note template. Example: base/project.md. |
formulas | map of string values | Named values that can reference other variables. Reusable across the template. |
fill | map of values | Slot values supplied by a child note template or snippet call. Values can include template references. |
The output and filename fields accept the same variable references as the template body.
Variable functions
All dynamic content uses the syntax {{function("argument")}}. Double braces, function name, arguments in parentheses. String arguments should be quoted.
| Token | Purpose |
|---|---|
{{prompt("Label")}} | Opens a text input with the given label. Returns the typed value. |
{{suggest("Option 1", "Option 2", label="Label")}} | Opens a picker with the listed options. The label= named argument is required. |
{{suggest_files("folder/", label="Label")}} | Opens a picker listing files in the given vault folder. Returns the selected file's path. |
{{suggest_props("folder:property", label="Label")}} | Opens a picker listing unique values of a frontmatter property across files in the given folder. Returns the selected value. |
{{date("YYYY-MM-DD")}} | Current date, formatted using moment.js tokens. |
{{time("HH:mm")}} | Current time, formatted using moment.js tokens. |
{{cursor_selection}} | The text selected in the editor at the moment the command was invoked. Empty string if nothing is selected. |
{{snippet(name)}} | Includes another snippet at this position. Use the snippet's filename (without extension) or a path relative to the templates root. |
{{formulas.key}} | References the value of a formula declared in the config block. |
Prompt deduplication: if the same label appears more than once in a template (including across snippets and inherited note templates), the user is prompted exactly once and the value is reused everywhere.
Single-result auto-resolve: if suggest_files or suggest_props finds only one match, it resolves automatically and shows a notice rather than opening a picker.
Named arguments: suggest, suggest_files, and suggest_props require a label= named argument to set the picker's label. Example: {{suggest("draft", "review", "final", label="Status")}}.
Formulas
Formulas are declared in the formulas: map of the config block. They are named string values that can reference other variables, including other formulas.
type: note
output: projects/
filename: "{{formulas.slug}}"
formulas:
title: "{{prompt('Project title')}}"
slug: "{{formulas.title}}-{{date('YYYY')}}"
owner: "{{suggest_props('team:name', label='Owner')}}"
Formulas are referenced via {{formulas.key}} anywhere in the template (frontmatter, body, other formula values, output, filename). Unused formulas are never evaluated — their prompts are never shown.
Circular formula references are detected at parse time and reported as errors.
Inheritance
A note template can inherit from a parent note template using the extends key. The child template's config values and body are merged on top of the parent's.
Parent template:
```yaml:yes-templates
type: note
filename: "{{formulas.slug}}"
formulas:
slug: "{{prompt('Project slug')}}"
```
# {{formulas.slug}}
{{slot(content)}}
Child template:
extends: base/project.md
fill:
content: "{{prompt('Summary')}}"
Merge rules:
- Config scalar fields (
output,filename): child's value replaces parent's. - Formulas: child's keys override parent's keys with the same name; parent's other keys are inherited.
- Frontmatter: child's values replace parent's (scalars replace, arrays replace wholesale).
- Body: the root parent's body controls placement. Child body content is routed into the parent's
{{slot(content)}}.
Constraints:
- The documented inheritance model is for note templates. Use snippets for composition via
{{snippet(name)}}. - A child template that provides body content requires the parent chain to expose
{{slot(content)}}; otherwise Validate template reportsparent-missing-slot-content. - Maximum chain depth is 5 templates (root to leaf inclusive).
- Cycles are detected and reported as errors.
- The
extendspath is relative to the templates root folder.
Snippets
Snippets are templates with type: snippet. They are inserted into existing notes via the Insert snippet command, or composed into other templates via {{snippet(name)}}.
When a snippet is injected:
- Its frontmatter is merged into the target note's frontmatter. Arrays are unioned (new values appended, duplicates removed). Scalar values replace the existing value.
- Its body replaces the current selection, or is inserted at the cursor if nothing is selected.
Snippet frontmatter that is empty (no keys) is ignored — the target note's frontmatter is untouched.
Slots and fills
Slots mark insertion points in note templates and snippets. Fills provide the content for those slots.
| Syntax | Purpose |
|---|---|
{{slot(content)}} | Inserts the content fill. Parent note templates use this to place child body content. |
{{slot(title)}} | Inserts a named fill. |
{{fill(title)}}...{{end}} | Provides a named fill from body content. |
fill: | Provides named fills from the config block. |
{{snippet(card, title="Hello")}}Body{{end}} | Invokes a snippet block. Named args and fill blocks can satisfy the snippet's slots; leftover block body becomes content. |
slots: and params: config keys are reserved for future declarations and are currently ignored.
First-run experience
When you invoke any command before configuring a templates folder, a modal appears offering to open plugin settings. Once you set a templates folder and return to the vault, the commands are immediately available.
The Validate template command is the one exception — it runs on any open file without requiring a templates folder to be set, though snippet and extends references cannot be resolved until a folder is configured.
Settings
| Setting | Default | Description |
|---|---|---|
| Templates folder | (none) | Vault-relative path to the folder that contains your template files. Required before any command will run. |
| Default filename pattern | (none) | Fallback filename pattern when a template does not specify filename:. Supports the same variable syntax as template filename fields. |
| Open behavior: Create note from template | Open in current pane | What to do with the new note after creation. Options: Open in current pane, Open in new pane, Don't open. |
| Open behavior: Create linked note from template | Don't open | What to do with the new note after creating a linked note. Defaults to "Don't open" because you are typically editing the source note. |
| Selection behavior: Create note from template | Copy selection to new note | When the template uses {{cursor_selection}} and you have text selected: Copy leaves the source untouched; Cut removes the selection from the source after the new note is created. |
FAQ and troubleshooting
Why does Validate template show warnings instead of errors for some issues?
When you run Validate template on a file that is outside your templates folder (or when no templates folder is configured), the plugin treats the file as a hypothetical template. References to snippets or parent templates that cannot be resolved are reported as warnings rather than hard errors, because the plugin cannot confirm whether those files exist. Once the file is inside your templates folder, unresolvable references become errors.
Can I have multiple templates folders?
No — the plugin supports a single templates folder. Use subfolders within it to organize your templates (e.g., templates/meetings/, templates/projects/, templates/snippets/). Type inference works on subfolder names: files inside a folder named snippets are treated as snippets without needing type: snippet in the config block.
Does the plugin work on mobile?
Yes. All features work on iOS and Android. The plugin uses only native Obsidian APIs with no desktop-specific dependencies.
Template changes are not showing up in the picker.
The plugin indexes your templates folder automatically and updates the index when files change — no reload is needed. If a template is missing from the picker, run Validate template on the file to check for parse errors. A template with parse errors is excluded from the index until the errors are fixed.
A template prompt fires more than once for the same label.
Each unique label should be prompted exactly once. If you are seeing a label prompted multiple times, it may mean two different references use the same label but with different arguments (function type, options, etc.) — which is a parse error. Run Validate template to confirm; it will identify the duplicate label and where both references appear.
The filename was changed when I created a note.
Obsidian filenames cannot contain certain characters (\ / : * ? " < > |). If your template's filename pattern resolves to a value containing any of these, the plugin replaces them with - and shows a notice explaining what was changed.
Planned direction
Planned work is grouped around template-language clarity, richer authoring feedback, release tooling, and long-term Obsidian Community Plugins readiness. These are direction categories, not a schedule.
Security
For vulnerability reporting and supported security scope, see SECURITY.md. Please avoid posting exploitable details in public issues.
License
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.