pi-prompt-composer

Build multi-option slash commands from plain prompts — variable expansion, arg collection & interactive selectors for Pi

Packages

Package details

extensionskill

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

License

MIT