# Prompt Template Anatomy


Drop a Markdown file named `review.md` into a `prompts/` directory and `/review` becomes a command you can run inside a session. Type it, and kli takes the file's body, fills in any arguments you passed, and submits the result as your next message to the model. A prompt template is a saved message you give a name. This page explains the parts of that file and how kli reads them, so you know exactly what `/review` will send before you run it.

## The file is the command

kli discovers prompt templates by scanning two directories for `*.md` files:

- `~/.config/kli/prompts/` — global templates, available in every project.
- `<repo>/.kli/prompts/` — project templates, available only when you start kli inside that project.

The scan is non-recursive. Only files directly in `prompts/` are read; subdirectories are ignored. The global directory is scanned first, then the project directory, so project templates extend the global set and a project file can shadow a global one of the same name.

The command name is the filename with `.md` removed. `review.md` is `/review`; `fix-ci.md` is `/fix-ci`. There is no name field in the file and no registry to edit. To rename the command, rename the file. To add one, add a file. This is why a template needs no installation step: putting it in the directory *is* the registration, and removing it unregisters the command.

## What the frontmatter carries

A template may open with a YAML frontmatter block — a `---` line, key/value pairs, a closing `---`. kli reads two keys from it, and only two.

**`description`** is the one-line summary shown when you list commands. It tells you and your collaborators what `/review` does without opening the file. If you omit it, kli derives a description from the first non-empty line of the body, truncated past 60 characters. A written description is worth the line, because the fallback is whatever happens to be your opening sentence.

**`argument-hint`** is the usage string shown beside the command, the part that reminds you what to type after the name — `<file>` or `[branch] [base]`, for instance. It is documentation for the human running the command. It does not validate or parse anything; the body decides how arguments are actually used.

Every other frontmatter key is ignored. The frontmatter is read as flat key/value pairs, and surrounding quotes on a value are stripped. If the file has no complete `---` … `---` fence, kli treats the whole file as body and the frontmatter as empty — so a template with no frontmatter at all still works, it just has a derived description and no hint.

## The body is the message, not a note to the model

Everything after the frontmatter is the template body. When you run the command, the body (with arguments substituted in) is submitted as your user message and enters the conversation exactly as if you had typed it. The model sees the expanded text. It does not see the file, the filename, or the frontmatter.

The command record itself is marked not model-visible. This is deliberate, not an oversight. The expansion already arrives as the user message through the normal submit path, so a visible command record would prepend a second, duplicate copy of the same text onto the very message the template just sent. Hiding the record keeps one message in the log: the expanded body, attributed to you. The transcript still shows the command line you typed, so you can see that `/review src/parser.ts` is what produced the message.

The practical consequence: write the body as the message you want the model to receive, not as instructions about the message. "Review the changes in $1 for correctness and style" is what the model reads. There is no separate layer where you describe the prompt to the agent; the body and the prompt are the same text.

## Loading is fail-soft, and bounded

kli reads templates at startup, and a bad file does not break the set. If one template is unreadable or malformed, loading it yields nothing and that file is skipped; the rest of your templates still register. A typo in one file's frontmatter costs you that one command, not all of them.

One file can be rejected on size. A template body flows verbatim into the model's context, so a single oversized file read at discovery could exhaust the space the conversation needs. kli caps a prompt template at 2 MiB; a file over the limit is skipped like any other unreadable one. Prompt templates are short messages, so the cap sits far above any reasonable template and exists to contain accidents, not to constrain real use.

## Related

- [Write a prompt template](/kli/extend/prompt-templates/write-your-first) — a recipe for creating one.
- [Argument substitution](/kli/extend/prompt-templates/using-arguments) — how `$1`, `$ARGUMENTS`, and slices expand in the body.
- [Run commands and eval Lisp](/kli/guides/run-commands-and-eval-lisp) — running commands inside a session.
