Plugins · CCPP PQL
CCPP PQL: Prompt Query Language
PQL is a structured language for prompting Claude Code. A prompt that starts with $ is a program, checked and compiled before Claude reads it.
A free-form prompt mixes what to change, where, under which constraints and when to stop. PQL (Prompt Query
Language) gives each of those a keyword. Start a prompt with $ and Claude Code's prompt box becomes a PQL
editor: the program is colored as you type, errors show above the box, and on Enter ccpp pql compile turns it
into a precise natural-language prompt. A program with an error never reaches Claude.
$ FROM @packages {
SESSION SUCCESS "The parser yields a valid AST for every supported input";
STOP WHEN "A secret needed by the next action is missing from the expected environment";
!ts-no-any;
HOW {
LIMIT FILE TO 250 LINES;
FOLLOW KISS, YAGNI;
PACKAGES NO_NEW;
}
MAKE @packages/parser {
ADD "A lexer", "A parser and its AST";
}
}Claude works in packages, creates packages/parser, adds two features there, keeps files under 250 lines without
new dependencies, respects the CPO policy ts-no-any, stops if a secret is missing, and declares success only
when the criterion holds. You keep seeing what you typed; Claude reads the compiled prompt.
Install
PQL needs the ccpp CLI and Claude Code 2.1.306 or later (the plugin is a hooks module).
curl -fsSL https://s3.ccpp.dev/ccpp-public/install.sh | sh
claude plugin marketplace add https://s3.ccpp.dev/ccpp-public/marketplace.json
claude plugin install pql@ccppThen type $, a space, FROM @ and press Tab on a suggestion. Remove the $ and the box is a normal prompt
again. Without ccpp, a $ prompt is refused with a hint: an uncompiled program is never sent.
The language at a glance
| Role | Keywords | Page |
|---|---|---|
| Scope | FROM, MAKE | Scopes |
| Objective | ADD, REMOVE, MODIFY, REFACTOR, SKIP, CONTINUE | Objectives |
| Condition | IF HAPPEN, IF NOT HAPPEN, ELSE IF …, ELSE | Conditions |
| Stop rules | SESSION SUCCESS, STOP WHEN, ASK WHEN | Stop rules |
| HOW | HOW { }, LIMIT, FOLLOW, PACKAGES, NAMING… | HOW directives |
| Policies | !policy-id; | Policy references |
| Functions | #name(...), .pql files, FOR | Functions |
Every keyword, directive and registered identifier fits on one page: the identifier cheatsheet.
What the compiler guarantees
The compiler is code, not a model. Every stage reports diagnostics, and any error blocks the whole prompt:
prompt ─▶ parse ─▶ expand (#calls, FOR, {{ }}) ─▶ validate ─▶ resolve (@paths, scopes) ─▶ project (!policies) ─▶ render- Syntax and types. Every statement ends with
;or a block, every parameter has a type:FROM "x"is an error,FROM @xis a directory reference. - The file system.
FROMtargets must exist,MAKEtargets must not, and no scope leaves the project or its parent scope, even through a symbolic link. - Conflicts. Two naming conventions for one category,
PACKAGES ALLOWunder an inheritedNO_NEW, a looser bound than one in force: reported, never silently overridden. - Policies. A
!policyreference is checked against the CPO policies installed for the project.
Descriptions in quotes (objectives, conditions, criteria) are never evaluated by the compiler: Claude establishes whether they hold. Quoted text is data for Claude, never an instruction about the protocol.
After the submission
Until the next PQL prompt or /pql reset, file writes (Write, Edit, MultiEdit, NotebookEdit) outside every
scope of the program are refused. Reading stays free. See Prompt mode.
The same compiler runs in a terminal: ccpp pql compile program.pql prints the prompt Claude would read
(CLI).