← Pi Agents

Prompt Templates

Prompt templates turn a Markdown file into a slash command with shell-style argument substitution; here is the frontmatter, the substitution table, and where templates load from.

The /review you typed in chapter 11 was real — it lives at .pi/prompts/review.md, four lines of frontmatter and three of body. This chapter is about everything that file can do and, just as importantly, what it cannot.

The one-line summary from prompt-templates.md: templates turn Markdown files into reusable / commands, and you want one when you would otherwise retype the same prompt without adding executable behaviour or a larger set of supporting instructions.

The file

---
description: Review uncommitted git changes
argument-hint: "[focus]"
---
Review the uncommitted git changes (`git status --short`, `git diff`).
Focus on ${1:-correctness, security, and error handling}.
Keep findings short, ordered by severity, each with the file path.

The filename becomes the command name, so review.md is available as /review. description appears in command completion; if you omit it, Pi uses the first non-empty line.

argument-hint is optional. Use <angle brackets> for required arguments and [square brackets] for optional ones — so [focus] renders in the completion menu as optional and npm run <suite> renders as required.

Run /reload after adding or changing a template in an active session.

Substitutions

Syntax Result
$1, $2, … One positional argument
$@ or $ARGUMENTS All arguments joined with spaces
${1:-default} First argument, or a default value
${@:-default} All arguments, or a default value
${@:N} Arguments starting at position N
${@:N:L} L arguments starting at position N

${1:-default} is the workhorse. Here is the whole mechanism in one place — the same template file, invoked three ways:

/review
/review concurrency
/review "API compatibility"
Review the uncommitted git changes (`git status --short`, `git diff`).
Focus on correctness, security, and error handling.
Keep findings short, ordered by severity, each with the file path.
Review the uncommitted git changes (`git status --short`, `git diff`).
Focus on concurrency.
Keep findings short, ordered by severity, each with the file path.

The second block is the first one with an argument: one line changed, and it changed because the argument arrived. Without the :- default the bare /review would expand with a literal hole where correctness now sits.

Arguments follow shell-like quoting, so the third invocation supplies one argument containing a space rather than two. That is how you pass a phrase without it splitting.

An expansion worth using

---
description: Draft a short implementation plan
argument-hint: "<goal>"
---
Draft a short implementation plan for: ${1:-<describe the goal>}.

Output exactly three sections:
1. Steps (numbered, smallest useful order)
2. Files to touch (paths in this repo)
3. How to verify (commands + what success looks like)

The default value is not filler. It tells the model what shape of input is expected when the argument is missing, which is the same trick chapter 10 used for acceptance checks.

${@:2} is the other one worth knowing — it lets a template pass the tail of its arguments to a second command in the same body:

---
description: Review the diff with a focus and a severity floor
argument-hint: "<focus> [min-severity]"
---
Run /review with focus "${1:-correctness}".
Then run /plan with: ${@:2}

When the expansion happens

how-pi-works.md places templates precisely: prompt templates expand editor input before it becomes a user message. prompt-templates.md adds one important detail:

Pi expands the template before the resulting text enters the agent. Extensions receive the raw input first through the input event unless an extension command with the same name handles it.

So an extension registering a command named review wins over the template of the same name, and otherwise an extension’s input handler sees /review concurrency before expansion. If you are debugging a template that appears not to expand, check whether an extension has claimed the name.

Where templates load from

A template can come from personal configuration, project configuration, an explicit path, or a Pi package. Project configuration loads only after project trust is granted.

pi --prompt-template ./review.md
pi -np --print "/review"   # -np disables discovered templates; explicit paths still load

Project templates become commands in the editor after trust is granted. Review their content before trusting an unfamiliar project — a template is text a human chose to run, but it is still text you did not write.

Discovery has a quirk

Conventional prompt directories load direct .md children only. Nested Markdown files need to be selected explicitly through settings or a package manifest, which can narrow discovery with explicit paths and globs.

{
  "packages": [
    {
      "source": "./my-templates",
      "prompts": ["./deep/nested/*.md"]
    }
  ]
}

If a template you wrote does not appear in the / menu, check the nesting before you check the syntax.

The running example: /review

Back to the review guard. This is chapter 11’s case 2, unchanged, and what it does and does not buy you:

  • It saves the wording. Worth having.
  • It takes a focus argument, and ${1:-correctness, ...} is what makes /review usable with no argument at all.
  • It does not run the repository’s checks before reviewing. That needs a command, and a template cannot issue one except by asking the model to.

Wrong: “a skill is a prompt template that the model fills in.” Correct: a template expands when you type its name, every time. A skill is advertised to the model by description and loaded only when the task matches, and skills.md is blunt that “A model might fail to load a relevant skill” — which is why /skill:name exists.

Keep templates narrow

The documentation’s own framing is the constraint: no executable behaviour, no larger set of supporting instructions. A template that grows past a screen and starts referring to files is telling you it wanted to be a skill.

That is not a stylistic preference. The gap is mechanical: a template is one file with no directory beside it, so a bundled checklist or a script it needs to run has nowhere to go. Chapter 13 exists because of that shape, not because a skill is a template done properly.