Turn a Markdown file into a /review command
Write the smallest prompt template, expand /review bare and with an argument, and see what an extension of the same name changes.
The /review from chapter 11 is a four-line Markdown file. This page writes the
smallest prompt template that matters, expands it for a bare /review and for one
argument, and then shows the two ordering rules behind “my template does not expand”.
This is documented Pi 1.0.4 behaviour, confirmed by a session test.
Write the template
Save this as ~/.pi/agent/prompts/review.md (or <project>/.pi/prompts/review.md),
then run /reload in an active session. It is the chapter’s template, unescaped for
readability:
---
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 is the command name, so review.md is /review. description shows in
completion; omit it and Pi uses the first non-empty line. In argument-hint,
<angle brackets> mark a required argument and [square brackets] an optional one.
${1:-default} is the workhorse: it reads the first argument, or supplies the default
when there is none. $@ and $ARGUMENTS are every argument joined by spaces.
One worked expansion
A bare /review leaves the default in place:
Focus on correctness, security, and error handling./review concurrency replaces exactly that line:
Focus on concurrency.Arguments follow shell-like quoting, so /review "API compatibility" supplies one
argument containing a space, not two. The full substitution table, seen in one
template invoked as /t a b c, is $1 → a, $2 → b, $@ and $ARGUMENTS →
a b c, ${@:2} → b c, ${@:2:1} → b, and ${9:-none} → none.
Expected outcome
| The model is asked to run | The user message that arrives | Why |
|---|---|---|
/review |
the default focus line | ${1:-default} fills the hole |
/review concurrency |
Focus on concurrency. |
the argument arrives |
/review "API compatibility" |
one argument with a space | shell-like quoting |
These are expected expansions, not a transcript from your machine. The backing test
is an observed run: it starts a real AgentSession with a scripted provider and
asserts the text of the last user message the provider received.
Two rules for “it does not expand”
An extension command named review wins outright: the template is never expanded and
the model is not called, which the test pins with a zero call count. Separately, an
extension’s input handler sees the raw text, /review concurrency, before
expansion. So before blaming the template syntax, check whether an extension claimed
the name. Conventional prompt directories also load direct .md children only —
prompts/nested/deep.md is not discovered, while a file selected explicitly through
settings or a package manifest can be.
Mechanism and limitations
Documented: the pinned docs/prompt-templates.md specifies the frontmatter, the
substitution table, that expansion happens before the text enters the agent, and that
conventional directories load direct .md children only. Observed:
templates.test.ts drives a real session with a scripted provider and asserts the
default, the argument replacement, quoted-phrase handling, the whole substitution
table, command precedence, the raw input text, and nested-file non-discovery. It does
not show a real model choosing anything.
A template is one file with no directory beside it. It saves the wording; it does not run the repository’s checks, and a checklist or script it grows to need has nowhere to live. It is also text, not a boundary.
Understand this example
Copy this prompt into your AI tool. No code runs here.
Apply this example
Copy this prompt into your AI tool. No code runs here.