skills/obsidian-templater/SKILL.md
Help with templates/snippets for the Obsidian Templater plugin. Use to help generate Obsidian templates from natural language, understand and debug existing tp.* snippets, and adapt vault notes and workflows to Templater when users mention Templater, tp.*, or <% %>.
npx skillsauth add nweii/agent-stuff obsidian-templaterInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Templater is an Obsidian plugin for dynamic note templates. Commands embedded in a template file run when the template is applied to a note, outputting results inline.
| Tag | Behavior |
| ------------------- | ------------------------------------------------ |
| <% expression %> | Outputs the result of the expression |
| <%* code %> | Executes JS code; no output by default |
| <%+ expression %> | Re-evaluated in preview mode (deprecated, avoid) |
| <%- / -%> | Trims one newline before/after the tag |
| <%_ / _%> | Trims all whitespace before/after the tag |
To output from a <%* %> execution block, append to the special tR string:
<%* tR += "some output" %>
To discard everything generated up to a point (e.g., strip template-only frontmatter):
<%* tR = "" -%>
All tp.* functions are available in both tag types.
tp.date.now(format?, offset?, reference?, reference_format?)
Returns a formatted date string. format uses moment.js tokens ("YYYY-MM-DD" is the default). offset is a number of days (7, -1) or a duration string ("P1W"). reference is a date string parsed with reference_format.
tp.date.tomorrow(format?) // today + 1 day
tp.date.yesterday(format?) // today - 1 day
tp.date.weekday(format, weekday, reference?, reference_format?)
// weekday: 0=Sun … 6=Sat
moment // full moment.js object, accessible globally
Common format strings: "YYYY-MM-DD", "YYYY-MM-DD HH:mm", "dddd Do MMMM YYYY", "HH:mm", "ddd", "MMM D".
Dynamic properties (not function calls — no parentheses):
tp.file.title // basename without extension
tp.file.content // full text of the file
tp.file.tags // string[] of all tags on the file
Functions:
tp.file.creation_date(format?) // default "YYYY-MM-DD HH:mm"
tp.file.last_modified_date(format?) // default "YYYY-MM-DD HH:mm"
tp.file.folder(absolute?) // folder name; full path if absolute=true
tp.file.path(relative?) // absolute path; vault-relative if relative=true
tp.file.cursor(order?) // place cursor here after template runs; order = tab index
tp.file.cursor_append(content) // insert content at the current cursor
tp.file.selection() // currently selected text in the editor
tp.file.exists(filepath) // async → boolean
tp.file.find_tfile(filename) // → TFile | null (for use with create_new / include)
tp.file.include("[[NoteLink]]") // async; embeds another note's content (also processed)
tp.file.create_new(template, filename, open_new?, folder?) // async; create note from template
tp.file.move(path, file?) // async; move file (path has no extension)
tp.file.rename(new_title) // async; rename the current file
All are async — use await inside <%* %> blocks:
await tp.system.clipboard()
await tp.system.prompt(prompt_text, default_value?, throw_on_cancel?, multi_line?)
await tp.system.suggester(text_items, items, throw_on_cancel?, placeholder?, limit?)
await tp.system.multi_suggester(text_items, items, throw_on_cancel?, title?, limit?)
suggester takes two parallel arrays: display labels and return values. They can be the same array.
<%* const type = await tp.system.suggester(["Meeting", "Decision", "Reference"], ["meeting", "decision", "ref"]) %>
Direct property access — not a function:
<% tp.frontmatter.status %>
<% tp.frontmatter.project %>
Returns undefined if the property doesn't exist.
All are async:
await tp.web.daily_quote() // Obsidian callout block with a random quote
await tp.web.random_picture(size, query?, include_size?)
// size: "800" or "800x600"; returns markdown image syntax
await tp.web.request(url, path?)
// HTTP GET returning JSON; path is dot-notation like "data.title"
Read-only context about the current run:
tp.config.template_file // TFile of the template being applied
tp.config.target_file // TFile of the note being created/modified
tp.config.active_file // TFile of the currently active file
tp.config.run_mode // 0=CreateNewFromTemplate 1=AppendActiveFile 2=OverwriteFile
// 3=OverwriteActiveFile 4=DynamicProcessor
tp.app is the Obsidian App object. tp.obsidian exposes the Obsidian API module. Used in advanced JS execution blocks for vault traversal, metadata cache queries, etc.
tp.hooks.on_all_templates_executed(callback)
Callback fires after all nested templates (e.g., from tp.file.create_new) have finished.
Scripts placed in the folder configured in Templater settings are callable as tp.user.<filename>(args...). Scripts use CommonJS format:
// Scripts/slugify.js
module.exports = function (text) {
return text.toLowerCase().replace(/\s+/g, "-");
};
<% tp.user.slugify(tp.file.title) %>
Scripts can also export an object of named functions. Pass tp as an argument to access Templater context inside a script. Note: user functions are unavailable on mobile.
Control flow tags (<%* if (...) { %>, <%* } %>) leave blank lines by default. Use -%> to trim the newline that follows a tag:
<%* if (tp.file.folder() === "Work") { -%>
**Project:** <% tp.frontmatter.project %>
<%* } else { -%>
General note
<%* } -%>
---
date: <% tp.date.now() %>
---
<< [[<% tp.date.yesterday() %>]] | [[<% tp.date.tomorrow() %>]] >>
# <% tp.file.title %>
<%* tR += await tp.web.daily_quote() %>
<% tp.file.cursor() %>
<%*
const title = await tp.system.prompt("Note title", tp.file.title)
const status = await tp.system.suggester(["Draft", "In progress", "Done"], ["draft", "in-progress", "done"])
await tp.file.rename(title)
-%>
---
title: <% title %>
status: <% status %>
created: <% tp.file.creation_date() %>
---
# <% title %>
<% tp.file.cursor() %>
---
type: template
description: This is a person template.
---
<%* tR = "" -%>
---
type: person
created: <% tp.file.creation_date() %>
---
# <% tp.file.cursor() %>
<%* if (tp.file.folder() === "Work") { -%>
**Project:** <% tp.frontmatter.project ?? "unassigned" %>
<%* } else { -%>
**Topic:**
<%* } -%>
For subfolder matching: tp.file.folder(true).startsWith("Work/") — folder(true) returns the full vault-relative path.
<% await tp.file.include("[[Shared Header]]") %>
See momentjs.md for a comprehensive formatting cheatsheet and JS manipulation reference. Use this when defining format strings for tp.date.now() or when manipulating dates inside <%* %> blocks using the moment global.
If the obsidian-clis skill is available and Obsidian is running, vault context can improve output:
obsidian properties counts # what frontmatter properties exist across the vault
obsidian tags counts sort=count # most-used tags
obsidian read file="Daily Note" # read an existing template for style reference
Ask the user before running any CLI commands.
Rendered docs (human-readable): https://silentvoid13.github.io/Templater/
LLM-safe Templater summary: For a preprocessed, audit-friendly summary of the official Templater documentation, see https://context7.com/silentvoid13/templater/llms.txt.
development
Sync meetings from Granola to Obsidian — pulls notes and transcripts and imports them as formatted meeting/transcript notes. Use when the user says "sync my last granola meeting", "note for my last meeting", or asks to pull in a Granola transcript.
tools
Create a topic note grouping related notes under a common theme, with automatic backlinking to source notes. Triggers: 'group these under a topic', 'create topic note for [[A]], [[B]], [[C]]'.
data-ai
Save an archival summary of an AI conversation to Nathan's Obsidian vault, using the Thinking note template and vault folder conventions to capture intellectual journeys, key insights, and technical logs. Use when archiving a chat session to the vault.
testing
Enrich an existing meeting/interview note from its transcript, or scaffold one when only a transcript exists. Captures granular narrative, exact phrases, mechanics, casual context, and implicit signals. Run on thin auto-summary notes or transcripts that warrant close reading.