Plugin System
Wai auto-detects and integrates with external tools through a flexible plugin architecture.
Built-in Plugins
Beads
- Detection:
.beads/directory - Description: Issue tracking with tasks, bugs, and dependencies
- Commands:
list,show,ready(read-only) - Hooks:
on_handoff_generate— Includes open issues in handoffson_status— Shows issue statistics
Example:
wai beads list # Pass-through to beads plugin
wai beads ready # Show issues ready to work on
Git
- Detection:
.git/directory - Description: Version control integration
- Hooks:
on_handoff_generate— Includes git statuson_status— Shows recent commits
OpenSpec
- Detection:
openspec/directory - Description: Specification and change management
- Integration: Status display shows active specs and change proposals with progress
Plugin Commands
Pass-through commands allow direct access to plugin functionality:
wai <plugin> <command> [args...]
Example:
wai beads list --status=open
wai beads show beads-123
Plugin Hooks
Plugins can inject context into wai workflows through hooks:
Available Hooks
| Hook | When Triggered | Purpose |
|---|---|---|
on_status | wai status called | Add plugin context to status output |
on_handoff_generate | wai handoff create called | Include plugin state in handoffs |
on_phase_transition | Phase changes | React to project phase changes |
Custom Plugins
Wai scans the .wai/plugins/ directory at your workspace root for any files with a .toml extension.
Example Plugin Definition
name = "my-tool"
description = "Custom tool integration"
[detector]
type = "directory"
path = ".mytool" # Relative to workspace root
[[commands]]
name = "list"
description = "List items"
passthrough = "mytool list"
read_only = true
[[commands]]
name = "sync"
description = "Sync data"
passthrough = "mytool sync"
read_only = false
[hooks.on_status]
command = "mytool stats"
inject_as = "mytool_stats"
[hooks.on_handoff_generate]
command = "mytool status --format=summary"
inject_as = "mytool_context"
Detector Types
- directory — Detect by directory presence. The
pathattribute is relative to the workspace root. - file — Detect by file presence. The
pathattribute is relative to the workspace root. - command — Detect by command availability. The
path(orcommand) attribute is the shell command to execute (must return exit code 0).
Note: For the
commanddetector in TOML, use thepathfield to specify the command to run (e.g.path = "mytool --version").
Command Attributes
- name — Command name (e.g.,
list) - description — Human-readable description
- command — Shell command to execute
- read_only — Whether command modifies state (respects
--safemode)
Managing Plugins
List All Plugins
wai plugin list
Shows:
- Plugin name and description
- Detection status (detected/not found)
- Available commands
- Configured hooks
Enable/Disable Plugins
wai plugin enable my-tool
wai plugin disable my-tool
Note: Built-in plugins cannot be disabled.
JSON Output
Get structured plugin information:
wai plugin list --json
Returns:
{
"plugins": [
{
"name": "beads",
"description": "Issue tracking",
"detected": true,
"commands": ["list", "show", "ready"],
"hooks": ["on_status", "on_handoff_generate"]
}
]
}
Safe Mode
Plugin commands that modify state are blocked in safe mode:
wai beads list --safe # OK - read-only
wai my-tool sync --safe # Blocked if not read_only
Plugin Troubleshooting
Plugin Not Detected
Symptom: wai plugin list shows plugin as “not detected”
Common Causes:
-
Detector file/directory missing
# Check if detector path exists ls -la .beads/ # for beads plugin ls -la .git/ # for git plugin ls -la openspec/ # for openspec plugin -
Plugin tool not installed
# Verify tool is available which beads which mytool # Install if missing cargo install beads -
Custom plugin TOML syntax error
# Validate TOML cat .wai/plugins/my-plugin.toml # Check for common issues: # - Missing required fields (name, description, detector) # - Wrong detector type (must be: directory, file, or command)
Plugin Command Fails
Symptom: wai <plugin> <command> returns error
Debugging Steps:
# 1. Verify plugin is detected
wai plugin list | grep myplugin
# 2. Test command directly
mytool command args
# 3. Check command definition
wai plugin list --json | jq '.plugins[] | select(.name=="myplugin") | .commands'
# 4. Verify passthrough is in PATH
which mytool
# 5. Check for command output issues
mytool command 2>&1 | head
Custom Plugin Not Loading
Symptom: Custom plugin in .wai/plugins/ doesn’t appear
Checklist:
- ✅ File has
.tomlextension - ✅ File is in
.wai/plugins/directory - ✅ TOML syntax is valid
- ✅ Required fields present:
name,description,detector - ✅ Detector path exists (for directory/file detectors)
Example Valid Plugin:
name = "example-tool"
description = "Example tool integration"
[detector]
type = "directory"
path = ".example"
[[commands]]
name = "status"
description = "Show status"
passthrough = "example status"
read_only = true
[[commands]]
name = "sync"
description = "Sync data"
passthrough = "example sync"
read_only = false
[hooks.on_status]
command = "example stats"
inject_as = "example_stats"
Hook Output Not Showing
Symptom: Plugin hooks defined but output doesn’t appear in status/handoffs
Debugging:
# 1. Check if plugin is detected
wai plugin list | grep myplugin
# 2. Verify hook command runs successfully
example stats # Run hook command directly
# 3. Check hook definition
wai plugin list --json | jq '.plugins[] | select(.name=="example") | .hooks'
# 4. Look for hook output in status
wai status -v # Verbose mode shows more detail
# 5. Check JSON output for hook_outputs
wai status --json | jq '.hook_outputs'
Permission Errors
Symptom: “Permission denied” when running plugin commands
Solutions:
# 1. Check plugin tool permissions
ls -l $(which mytool)
# 2. Verify tool is executable
chmod +x $(which mytool)
# 3. For safe mode issues, check read_only flag
wai plugin list --json | jq '.plugins[] | select(.name=="myplugin") | .commands[] | {name, read_only}'
Detector Not Working
Symptom: Plugin should be detected but shows as “not detected”
Detector Types and Requirements:
Directory Detector:
[detector]
type = "directory"
path = ".mytool" # Directory must exist at workspace root
Check: ls -la .mytool/
File Detector:
[detector]
type = "file"
path = "mytool.config" # File must exist at workspace root
Check: ls -la mytool.config
Command Detector:
[detector]
type = "command"
path = "mytool --version" # Command must exit 0 and be in PATH
Check: which mytool && mytool --version
Getting Help
If you can’t resolve plugin issues:
# Create debug report
{
echo "=== Plugin List ==="
wai plugin list
echo -e "\n=== Plugin JSON ==="
wai plugin list --json
echo -e "\n=== Custom Plugins ==="
ls -la .wai/plugins/
echo -e "\n=== Doctor Check ==="
wai doctor
} > plugin-debug.txt
File an issue at https://github.com/charly-vibes/wai/issues with plugin-debug.txt attached.
See Also
- Commands Reference - Plugin management commands
- Troubleshooting - Plugin-specific troubleshooting
- JSON Output - Plugin JSON schema