Plugins · CCPP PQL
Prompt mode
How the pql plugin turns Claude Code's prompt box into a PQL editor: colors, completion, diagnostics, compilation and the scope guard.
The pql plugin is a Claude Code hooks module. No command is needed: a prompt whose first character is $ is
a PQL program, and removing the $ restores the normal prompt.
──────────────────────────── PQL MODE ────────────────────────────
✗ 2:24 PQL-S005 Expected `;` to end the instruction.
$ FROM @packages/pql {
ADD "The PQL lexer"
}
◆ PQL Mode · ✗ 1 errorColors
Colors are theme keys, so they follow your Claude Code theme.
| Element | Theme key |
|---|---|
$, FROM, MAKE, @paths | permission |
Objectives, #calls | claude |
| Conditions, numbers | warning |
Stop rules, !policies | merged |
HOW and directives | planMode |
Registered identifiers (FILE, KISS, camelCase) | ide |
Connectors (TO, OVER, NO_NEW), IN, RANGE | inactive, italic |
| Strings | success; interpolations diffRemoved |
| Comments | dimmed, italic |
Keywords are bold. Errors and warnings are underlined.
Completion
Suggestions appear above Claude Code's own; Tab takes one. What is offered depends on the cursor:
- Start of a statement: only the keywords allowed there. A fresh program offers
FROMandMAKE; a block's preamble addsSTOP WHEN,ASK WHEN,HOWand the directives; after an objective, a condition or a scope, only executable keywords;SESSION SUCCESSonly at the root; insideHOW { }only directives; after the}of anIFbranch, theELSEforms come first. - Second word of a phrase:
STOPthenWHEN,ELSEthenIF HAPPEN,DEPTHthenMAX. - Inside a directive:
LIMITcategories, thenTO, then the units valid for the category;NAMINGcategories then conventions; principles not used yet afterFOLLOW;PACKAGESmodes; metrics and modes. #the active functions, with their signature.!the active CPO policies.- Nothing inside strings, comments, interpolations or numbers, and after
@Claude Code's own path popover takes over.
Completion fires for a non-empty word: after a space, type a letter. Functions and policies come from
ccpp pql catalog --json, loaded at session start and refreshed every 30 seconds at most.
Diagnostics
The PQL MODE band above the box shows up to three diagnostics, errors first, as line:column code message
((+N more) when there are others). The line under the box shows the status:
| Status | Meaning |
|---|---|
◆ PQL Mode · start with FROM or MAKE | Empty program |
◆ PQL Mode · ✓ Valid syntax | No error |
◆ PQL Mode · ✗ 2 errors | Enter will refuse the prompt |
The box only checks what needs no file system. @ targets, functions and policies are checked on Enter.
Submission
On Enter the plugin pipes the whole prompt to ccpp pql compile --json in the session directory.
- Success: your PQL stays the visible message, and Claude receives the compiled prompt as context.
- Errors: the prompt is dropped with a one-line list (
1:8 PQL-R001 message | …) and your draft stays in the box. ccppmissing or failing: dropped with a hint. An uncompiled program is never sent.
The plugin runs its own bin/ccpp launcher: the binary in libexec/ when the marketplace is bundled, otherwise
the ccpp on PATH.
Scope guard
A compiled program records its scopes. Until the next PQL prompt or /pql reset, a Write, Edit, MultiEdit or
NotebookEdit call whose file lies outside every scope is denied, with the reason. Reading stays free.
- The scopes of a program form a union; a scope inside a condition branch counts.
- A program without a scope falls back to the session directory.
- Paths are normalized lexically (
.,..); symbolic links are not resolved here (the compiler already checked them).
/pql prints the active program (its normalized form) and its scopes. /pql reset clears them and lifts the
guard.
Limits
- Hooks modules cannot recolor the prompt border: the band and the status line stand in for it.
- The guard does not see Bash or MCP tools, and nested scopes do not narrow the union. For hard gates on those, use CPO.
- The active program lives in the module: reloading the plugin forgets it.