pi-prompt-composer
Build multi-option slash commands from plain prompts — variable expansion, arg collection & interactive selectors for Pi
Package details
Install pi-prompt-composer from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-prompt-composer- Package
pi-prompt-composer- Version
1.9.1- Published
- May 12, 2026
- Downloads
- 1,794/mo · 916/wk
- Author
- victor-founder
- License
- MIT
- Types
- extension, skill
- Size
- 140.8 KB
- Dependencies
- 1 dependency · 2 peers
Pi manifest JSON
{
"extensions": [
"./extensions"
],
"skills": [
"./skills"
],
"image": "https://raw.githubusercontent.com/victor-software-house/pi-prompt-composer/main/assets/preview.png"
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-prompt-composer
Build composer-owned slash commands from plain Markdown prompts — flat files, grouped menus, typed args, Liquid templating, and visible dispatch for Pi.
Turn .md files under composed/ into single slash commands, or turn directories into grouped commands with Tab-completable subcommands, a rich interactive selector, automatic missing-argument collection, and optional Liquid-powered rendering.
Quick start
# Install
pi install pi-prompt-composer
# Copy the bundled examples into your project composer root
mkdir -p .pi/composed/review
cp -r $(pi resolve pi-prompt-composer)/examples/prompts/review/* .pi/composed/review/
# Reload Pi, then try:
# /review → interactive selector
# /review summary → asks for missing "change" arg, then sends
# /review fix "bug" → dispatches immediately
# Or create a single Liquid-powered command
cat > .pi/composed/ship.md <<'EOF'
---
description: Prepare a ship checklist
engine: liquid
args:
- name: change
required: true
hint: What changed?
---
Prepare release checklist for {{ args.change | quote }}.
{% xml "checks" %}
- typecheck
- lint
- tests
- docs
{% endxml %}
EOF
# /ship --change "composed prompt discovery"
How it works
Composer-owned prompts live under composed/ roots so Pi does not also load them as native flat prompts.
.pi/composed/
├── review.md ← /review
└── review/
├── _index.md ← /review
├── summary.md ← /review summary
└── fix.md ← /review fix
Composer roots:
- User:
~/.pi/agent/composed/ - Project:
<project>/.pi/composed/
Native Pi prompt roots (~/.pi/agent/prompts/*.md, .pi/prompts/*.md) stay native. Existing grouped prompts under prompts/<group>/ are migrated once into composed/<group>/ with a warning.
Features
| Feature | Behavior |
|---|---|
| Flat composer commands | .pi/composed/review.md → /review without creating a fake group |
| Grouped commands | .pi/composed/review/summary.md → /review summary |
| Liquid templating | engine: liquid unlocks if, for, where, map, join, structured XML blocks, JSON snippets, and command-batch rendering |
| Direct dispatch | /review fix "the bug" → substitutes args, sends immediately |
| Bare-command selector | /review → rich TUI selector with aligned descriptions and dynamic usage hints |
| Missing-arg collection | Prompts with required args metadata pause and ask before sending |
| Autocomplete | Tab after /review shows subcommand names with descriptions |
| Safe helpers | present, quote, tokens, json, shell_quote, and {% xml "tag" %} help build Claude Code skill-style prompts |
| Escape syntax | \$ARGUMENTS renders as literal $ARGUMENTS in engine: pi prompts |
| Discovery warnings | Malformed metadata and misplaced composer prompts surface as Pi notifications on session start |
Bundled /compose |
Built-in helpers for creating, extending, and simplifying grouped prompts |
| Authoring skill | Comprehensive compose-grouped-prompts skill loaded on demand for deep guidance |
Bundled /compose command
The package ships a built-in /compose grouped command for authoring grouped prompts:
| Command | Purpose |
|---|---|
/compose |
Interactive selector for compose operations |
/compose new <group-name> |
Create a new grouped prompt set |
/compose add <group-name> |
Add subcommands to an existing group |
/compose remove <group-name> |
Remove or simplify a subcommand |
The bundled /compose is loaded with lowest precedence. If you create your own compose/ group in user or project prompts, it overrides the built-in version.
Required tools
The /compose prompts work best with pi-ask-user installed — it provides the ask_user tool for interactive decision handshakes during prompt authoring. If required tools are missing, a persistent warning banner appears at session start:
Missing tools: ask_user — run pi install pi-ask-user
Authoring skill
The package also ships a compose-grouped-prompts skill with:
- Workflow guidance for creating, adding, and removing prompts
- Layout conventions and naming rules
- Frontmatter and args reference
- Realistic examples and anti-patterns
The skill is loaded on demand when the model needs deeper guidance beyond what the /compose prompts provide.
Writing prompts
_index.md (required for groups)
---
description: Review workflows
order: [summary, fix]
---
No type: group marker is required. A subfolder under composed/ with _index.md is a group.
order is optional — controls subcommand display order in autocomplete and the selector. Listed names appear first in the given order; unlisted subcommands are appended alphabetically. Omit for default alphabetical ordering.
Flat composer prompt files
---
description: Review a change
engine: liquid
args:
- name: change
required: true
hint: Change, diff, file, or PR to review
- name: focus
required: false
hint: Optional focus
---
Review {{ args.change | quote }}.
{% if args.focus | present %}
Focus on: {{ args.focus }}
{% endif %}
Save as .pi/composed/review.md, then run /review --change "auth fix" --focus security.
Nested prompt files
---
description: Summarize a change
args:
- name: change
required: true
hint: What changed?
- name: context
required: false
hint: Additional context
---
Summarize the following change:
$ARGUMENTS
Argument syntax defaults to Pi-native: $1, $2, $@, $ARGUMENTS, ${@:N}, ${@:N:L}. Add engine: liquid to use named args ({{ args.change }}), conditionals, loops, and filters.
Use \$ to escape a literal dollar sign (e.g., \$ARGUMENTS renders as $ARGUMENTS).
args metadata
Each item needs:
| Field | Required | Default | Notes |
|---|---|---|---|
name |
yes | — | Items without name are skipped with a warning |
required |
no | false |
Whether the extension asks for this arg when missing |
hint |
no | "" |
Shown in the input prompt and selector usage hint |
Parsing is lenient — a missing hint or required won't break the prompt. Only a missing name drops that individual arg item.
Liquid helpers
Liquid prompts get { args, argv, arguments, variables, prompt, now } as their render context:
{{ args.change | quote }}
{{ args.items | where: "kind", "risk" | map: "name" | join: ", " }}
{{ args.metadata | json: 2 }}
{{ args.workdir | shell_quote }}
{% xml "task" %}{{ args.goal }}{% endxml %}
Static constants belong in frontmatter variables, not repeated body literals or body-level assign statements:
variables:
repo_path: acme/app
review_channel: dev-review
Repo: {{ variables.repo_path }}
Channel: {{ variables.review_channel }}
Use body-level assign for dynamic derived values only, such as args.key | upcase.
Prompt-local partials live beside the prompt in _partials/ and can be included with {% include "name.md" %}. Use them for repeated prompt prose or JSON/tool snippets.
Liquid also gets raw positional context for Pi-like rest behavior: argv is the positional array and arguments is every positional joined by spaces. For nicer frontmatter, mark the final arg rest: true with type: string[] to capture remaining positionals.
args:
- name: group_name
required: true
hint: Group name
- name: description
required: false
type: string[]
rest: true
hint: Freeform description
Description: {{ args.description | join: " " }}
Raw argv: {{ argv | join: ", " }}
Useful helpers:
| Helper | Purpose |
|---|---|
present |
True for non-empty strings/arrays |
quote |
Trim and double-quote text |
tokens |
Rough chars/4 estimate |
json |
JSON stringify values, optionally pretty-printed |
shell_quote |
Single-quote shell arguments for command text |
{% xml "tag" %} |
Emit XML-style blocks only when rendered body is non-empty |
{% shell %}...{% endshell %} |
Render a command and optionally execute it when shell frontmatter opts in |
Shell execution is deny-by-default:
| Frontmatter | Behavior |
|---|---|
omitted / shell: deny |
Show command text; do not execute |
shell: ask |
Confirm before execution; stdout replaces the block |
shell: allow |
Execute without asking; trusted prompts only |
Configure the default in ~/.pi/agent/prompt-composer.json or project-local .pi/prompt-composer.json:
{
"shell": { "mode": "ask", "timeoutMs": 30000 }
}
Prompt frontmatter wins over config.
Shell blocks run with bash -lc from the prompt file directory, so relative scripts work:
{% shell %}
python3 scripts/summarize.py --topic {{ args.topic | shell_quote }}
{% endshell %}
This is opt-in because shell can read files, call networks, mutate repos, or expose secrets. Quote user-controlled args with shell_quote. Validate prompt roots before live smoke:
pnpm run prompts:validate
mise run prompts:validate -- prompts ~/.pi/agent/composed/review
See docs/TEMPLATING.md and examples/templating/README.md.
Composer does not pretend to sandbox commands. Portable sandboxing is platform-specific; shell-enabled prompts are trusted code, matching Pi's normal shell trust model.
What this package owns vs Pi-native
| Concern | Owned by |
|---|---|
| Frontmatter parsing, arg syntax, substitution | Pi (reused) |
| Folder → command grouping, selector, arg collection | pi-prompt-composer |
Native flat .md prompt behavior under prompts/ |
Pi (unchanged) |
Composer flat .md prompt behavior under composed/ |
pi-prompt-composer |
| Command precedence (grouped wins over flat) | Pi (extension commands take precedence) |
Known limitations
See docs/ISSUES.md for tracked defects and status.
Non-goals (this version)
- No default shell execution from templates; shell remains explicit opt-in
- No nesting deeper than
/group subcommand - No aliases or dynamic subcommands
Development
pnpm install
pnpm run typecheck && pnpm run lint && pnpm run test
Autofix: pnpm run fix · Watch: pnpm run test:watch
Related packages
| Package | Description |
|---|---|
@victor-software-house/pi-openai-proxy |
OpenAI-compatible HTTP proxy for Pi's multi-provider model registry |
