A comprehensive Neovim plugin for PDDL (Planning Domain Definition Language) — the standard input language for AI planners.
Features:
- 🔍 nvim-cmp autocompletion source
- 🤖 Integration with solver.planning.domains for running planners
- 📊 Beautiful plan visualization with syntax highlighting
- 💾 Automatic plan file saving (
.pddl) and result file saving (.txt) - 🎨 Syntax highlighting with action-specific colors and error linting
- 🚨 International character linting
- Features
- Requirements
- Installation
- Configuration
- PDDL Solver Integration
- Commands
- Autocompletion
- Snippets
- Syntax Highlighting
- Development
- License
| Category | What's completed |
|---|---|
| Top-level keywords | define, domain, problem |
| Domain sections | :requirements :types :constants :predicates :functions :action :durative-action :derived |
| Problem sections | :domain :objects :init :goal :metric |
| Requirements | All 20+ standard PDDL requirement flags |
| Action sub-keys | :parameters :precondition :effect :duration :condition |
| Logical operators | and or not imply forall exists when |
| Temporal operators | at start at end over all |
| Numeric operators | increase decrease assign scale-up scale-down |
| Comparison | > < >= <= = |
| Metric | minimize maximize total-time total-cost |
| Buffer variables | ?var names extracted from the current buffer |
| Buffer identifiers | predicate / object names extracted from the current buffer |
Context-aware: completions change depending on whether you are inside a domain
or problem file, inside :requirements, :action, :precondition, :effect,
:init, :goal, etc.
- 🌐 Connect to planning-as-a-service servers (e.g., solver.planning.domains)
- 🚀 Run any available planner (LAMA, Fast-Downward, dual-BFWS, etc.)
- 📊 Beautiful plan visualization with:
- Color-coded syntax highlighting per action type
- Visual flow arrows (START → steps → GOAL)
- Step numbering with progressive indentation
- Cost and metadata display
- Planner output logs
- 💾 Two output files saved automatically:
{domain}_{problem}_plan.pddl— the plan steps with emoji-formatted actions{domain}_plan-result.txt— the full rendered result buffer
- ⚡ Live progress bar with spinner during solving
- 🔄 Automatic polling for asynchronous solvers
- 🔁 Stdout fallback parsing when the API returns an empty plan field
- Neovim ≥ 0.9
- nvim-cmp
curl(for solver integration)
{
"ferisjuan/cmp-pddl",
ft = "pddl",
dependencies = { "hrsh7th/nvim-cmp" },
config = function()
require("cmp").setup.filetype("pddl", {
sources = require("cmp").config.sources({
{ name = "pddl" },
{ name = "buffer" },
}),
})
end,
}use {
"ferisjuan/cmp-pddl",
requires = { "hrsh7th/nvim-cmp" },
}local cmp = require("cmp")
-- Apply only to PDDL buffers
cmp.setup.filetype("pddl", {
sources = cmp.config.sources({
{ name = "pddl", priority = 1000 },
{ name = "buffer", priority = 500 },
}),
})require("cmp").setup({
sources = require("cmp").config.sources({
{ name = "nvim_lsp" },
{ name = "luasnip" },
{ name = "pddl" }, -- ← add this
{ name = "buffer" },
}),
})- Open a PDDL domain file and problem file in Neovim
- Run
:PddlSolve - Select a server (or add a new one)
- Select a planner
- Watch the beautiful plan appear!
╔════════════════════════════════════════════════════════════════╗
║ PDDL Plan Result ║
╚════════════════════════════════════════════════════════════════╝
📋 Server : https://solver.planning.domains:5001
🤖 Planner : lama-first
📊 Steps : 44
💰 Cost : 44
✓ Plan found successfully!
💾 Saved to : /path/to/blocksworld_blocksworld_plan.pddl
📄 Result : /path/to/blocksworld_plan-result.txt
┌─────────────────────────────────────────────────────────┐
│ START
│ ↓
│ 1. 📤 UNSTACK C E
│ ↓
│ 2. 📦 STACK C F
│ ↓
│ 3. ⬇️ PUT-DOWN E
│ ↓
│ 4. ⬆️ PICK-UP G
│ ↓
...
│ ↓
│ 🎯 GOAL
└─────────────────────────────────────────────────────────┘
The output features:
- 🎨 Color syntax highlighting (action-specific colors — see Syntax Highlighting)
- 📊 Metadata display (server, planner, step count, cost)
- ➡️ Visual flow showing progression from START to GOAL
- 💾 Auto-saved plan to
{domain}_{problem}_plan.pddl - 📄 Auto-saved result to
{domain}_plan-result.txt - 📝 Planner logs included at the bottom
Each action is formatted with:
- Number at column 0
- Progressive indentation: line N gets N spaces before the action
- Parentheses stripped
- Action keyword uppercased
- Emoji prefix per action type
1. ⬆️ PICK-UP A
2. 📦 STACK A B
3. 📤 UNSTACK C D
10. ⬇️ PUT-DOWN E
The words domain and problem are automatically stripped from filenames:
| Domain file | Problem file | Plan file | Result file |
|---|---|---|---|
blocksworld-domain.pddl |
blocksworld-problem.pddl |
blocksworld_blocksworld_plan.pddl |
blocksworld_plan-result.txt |
my-domain.pddl |
task-problem-01.pddl |
my_task-01_plan.pddl |
my_plan-result.txt |
Send your domain and problem to a PDDL planner and visualize the solution.
Usage:
- Open both domain and problem files
- Run
:PddlSolve - Select server and planner
- View the plan!
The command will:
- Automatically find domain/problem files in open buffers or current directory
- Validate the PDDL syntax before sending
- Show a live progress bar during solving
- Display the plan with beautiful formatting
- Save the plan to
{domain}_{problem}_plan.pddl - Save the full result buffer to
{domain}_plan-result.txt
Add a new planning server.
Default server: https://solver.planning.domains:5001
Usage:
:PddlAddServerThen enter the server URL and a friendly name.
List all saved planning servers.
Usage:
:PddlServersParse the current PDDL buffer and display its AST structure (useful for debugging).
Usage:
:PddlParseReload all cmp-pddl modules without restarting Neovim (useful during development).
Usage:
:PddlReloadThe plugin provides context-aware autocompletion:
- Domain files: Suggests domain sections (
:action,:predicates, etc.) - Problem files: Suggests problem sections (
:init,:goal, etc.) - Inside
:requirements: Shows all PDDL requirement flags - Inside actions: Suggests
:parameters,:precondition,:effect - Inside formulas: Suggests logical operators (
and,or,not, etc.) - Variables: Extracts and suggests
?varnames from the buffer - Predicates/Objects: Suggests identifiers defined in the buffer
Snippets use LSP snippet syntax (insertTextFormat = 2). For them to expand
you need a snippet engine registered with nvim-cmp, such as
LuaSnip or
vim-vsnip.
| Trigger | Expands to |
|---|---|
define-domain |
Full domain skeleton |
define-problem |
Full problem skeleton |
snippet-action |
:action block |
snippet-durative-action |
:durative-action block |
snippet-forall |
(forall ...) quantifier |
snippet-exists |
(exists ...) quantifier |
snippet-when |
(when ...) conditional effect |
The plugin ships a syntax/pddl.vim file that highlights:
- Keywords and section headers
- Requirement flags
- Variables (
?var) - Logical / temporal / numeric operators
- Comments (
;) - Numbers
All :word tokens (:action, :parameters, :requirements, etc.) are
highlighted in violet — distinct from plain identifiers and operators.
Actions in plan files and plan result buffers are highlighted with distinct colors per verb:
| Action | Color |
|---|---|
STACK |
Bright blue #89DDFF |
UNSTACK |
Steel blue #61AFEF |
PICK-UP |
Light amber #FFCB6B |
PUT-DOWN |
Deep amber #C78D3A |
Any word containing a non-ASCII character (e.g. café, naïve) is marked
with a red undercurl — the same style used by spell checkers. Standalone
emojis (used as action prefixes) are not flagged.
Custom highlights applied to the result buffer:
- Borders: Muted blue-gray box drawing
- Success/Error: Green/red status indicators
- Step numbers: Purple, bold
- Actions: Per-verb color (see table above)
- Arrows: Orange
- Metadata: Gray, italic
Automatically applied to every PDDL buffer:
- 2-space indentation
-treated as part of a word (for identifiers like:durative-action)- Comment string set to
; %s - Folding on parentheses with all folds open by default
cmp-pddl/
├── lua/cmp_pddl/
│ ├── init.lua # cmp source
│ ├── tokenizer.lua # PDDL tokenizer
│ ├── syntax_tree.lua # S-expression parser
│ ├── parser.lua # Domain/Problem extractor
│ ├── solver.lua # HTTP client for planning-as-a-service
│ └── commands.lua # :Pddl* commands
├── plugin/
│ └── cmp_pddl.lua # Entry point, registers everything
├── syntax/
│ └── pddl.vim # Syntax highlighting
└── ftplugin/
└── pddl.lua # Filetype settings
When developing the plugin:
-
Clone the repository:
git clone https://github.com/ferisjuan/cmp-pddl.git ~/path/to/cmp-pddl cd ~/path/to/cmp-pddl
-
Make your changes in the source files
-
Sync to your Neovim installation:
./dev-sync.sh
-
In Neovim, reload the modules:
:PddlReload
-
Test your changes immediately without restarting Neovim!
The plugin automatically handles module caching:
plugin/cmp_pddl.luaclearsvim.loadercache on load:PddlReloadcommand force-reloads all modules during developmentSourcePostautocmd ensures fresh loads after plugin updates
Submit a planning problem to a solver.
Parameters:
server(string): Server URL (e.g.,"https://solver.planning.domains:5001")planner(string): Planner ID (e.g.,"dual-bfws-ffparser","lama-first")domain(string): PDDL domain textproblem(string): PDDL problem textdomain_path(string, optional): Path to domain file (for plan saving)problem_path(string, optional): Path to problem file (for plan saving)
Returns: Nothing (displays result in a buffer)
Fetch available planners from a server.
Parameters:
server(string): Server URLcallback(function):function(planners, error)where planners is an array of{id, description}
If you see "goal already satisfied (0 steps)" but expect a plan:
- Check if using an old cached version:
:PddlReload - Verify domain and problem files are correctly loaded
- Check planner output logs (shown at bottom of result buffer)
The plugin includes a stdout fallback parser: if output.plan is empty, it
automatically extracts steps from the planner's raw stdout output.
If changes aren't taking effect:
- Run
:PddlReloadto force reload modules - For development, use
./dev-sync.sh+:PddlReloadworkflow - As last resort, restart Neovim
If solver connection fails:
- Verify internet connection
- Check server URL is correct (
:PddlServers) - Try the default server:
https://solver.planning.domains:5001 - Ensure
curlis installed:which curl
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly using the development workflow
- Submit a pull request
- PDDL specification: PDDL - The Planning Domain Definition Language
- Planning service: solver.planning.domains
- Inspired by pddl-workspace for VSCode
MIT