Testing Plugins
How to test your Han plugins locally before distribution, including validation, hook testing, and debugging.
Testing your plugin locally ensures it works correctly before sharing it with others. This guide covers validation, hook testing, and debugging techniques.
Plugin Validation
Han includes a built-in validator to check your plugin structure:
# Validate current directory
han plugin validate .
# Validate specific plugin
han plugin validate ./path/to/my-plugin
The validator checks:
- Required files exist -
.claude-plugin/plugin.json - plugin.json is valid - Valid JSON with required fields
- Naming conventions - Plugin name matches directory
- Hook configuration -
han-plugin.ymlsyntax is correct - Skill format - SKILL.md files have valid frontmatter
- Command format - Command files have required frontmatter
Validation Output
Validating plugin: biome
Checking required files...
.claude-plugin/plugin.json ... OK
han-plugin.yml ... OK
Checking plugin.json...
name: biome ... OK
version: 1.0.0 ... OK
description: present ... OK
Checking hooks...
lint: command valid ... OK
lint: dirs_with patterns valid ... OK
lint: if_changed patterns valid ... OK
Checking skills...
skills/getting-started/SKILL.md ... OK
Plugin validation passed!
Testing Locally
han plugin install resolves names against a marketplace; there is no --path flag for pointing it at a working directory. To exercise a plugin you are writing, work inside a checkout of the marketplace repository that registers it.
Method 1: Run From the Marketplace Checkout
Han discovers plugins through .claude-plugin/marketplace.json, so once your plugin is registered there you can drive it directly:
# From the plugin directory
han plugin validate
han plugin generate-hooks
# Then exercise the hook
han hook run my-plugin lint --verbose
han hook list --plugin my-plugin
Edits to han-plugin.yml take effect as soon as you regenerate hooks/hooks.json.
Method 2: Direct Configuration
Add your plugin directly to settings:
.claude/settings.json (project scope):
{
"permissions": {
"allow": []
},
"claudePlugins": {
"localPlugins": [
{
"path": "/absolute/path/to/my-plugin"
}
]
}
}
Testing Hooks
Run Hooks Manually
Test individual hooks with the han hook run command:
# Run a specific hook
han hook run my-plugin lint
# Run with verbose output
han hook run my-plugin lint --verbose
# Skip caching (force re-run)
han hook run my-plugin lint --no-cache
# Run in a specific directory only
han hook run my-plugin lint --only ./packages/web
Verify Hook Conditions
Test that hooks only run when expected:
# Create a test file
echo "const x = 1" > test.js
# Run hook - should execute
han hook run my-plugin lint --verbose
# Remove test file
rm test.js
# Run hook - should skip (no matching files)
han hook run my-plugin lint --verbose
Check dirs_with Filtering
# Without config file - hook should skip
rm -f biome.json
han hook run biome lint --verbose
# Expected: "Skipping: no config file found"
# With config file - hook should run
echo '{}' > biome.json
han hook run biome lint --verbose
# Expected: Hook executes
Check if_changed Filtering
# Modify a matching file
touch src/app.ts
# Run hook - should execute
han hook run my-plugin typecheck --verbose
# Without changes - should use cache
han hook run my-plugin typecheck --verbose
# Expected: "Using cached result"
Testing Skills
Verify Skill Loading
Skills are loaded automatically when relevant. To test:
- Start a Claude Code session with your plugin installed
- Ask about your skill's topic
- Claude should reference the skill content
Check Frontmatter
Validate skill frontmatter manually:
# Check SKILL.md has valid YAML frontmatter
head -20 skills/getting-started/SKILL.md
Expected output:
---
name: getting-started
description: Use when setting up my-tool...
allowed-tools: [Read, Write, Edit, Bash, Glob, Grep]
---
Testing Commands
Verify Command Registration
Commands should appear in Claude Code's command list:
- Start Claude Code session
- Type
/to see available commands - Your plugin's commands should appear
Test Command Execution
# In Claude Code
/my-command
# Claude should execute the command workflow
Testing Agents (Discipline Plugins)
Verify Agent Loading
- Install your discipline plugin
- Ask Claude about your agent's specialty
- Claude should offer to use the agent
Test Agent Behavior
Create a test scenario matching your agent's examples:
User: "Analyze the auth module for code quality issues"
Expected: Claude invokes your quality-analyzer agent
Testing MCP Servers (Integration Plugins)
Verify Server Configuration
Check your .mcp.json is valid:
# Validate JSON
cat .mcp.json | jq .
# Check server can be started
npx -y @your-org/mcp-server-your-service --help
Test Tool Availability
- Install your integration plugin
- In Claude Code, check available tools
- Your MCP server's tools should appear
Test Memory Provider
If you configured a memory provider, start the Han MCP server and call its memory tool from a Claude Code session:
han mcp
There is no han memory query subcommand. Bare han memory prints the memory system's status, and han browse gives you a searchable UI over indexed sessions.
Debugging
Verbose Mode
Enable verbose output for detailed information:
han hook run my-plugin lint --verbose
Check Hook Status
View hook configuration and state:
# Every configured hook, Han plugins plus Claude Code settings
han hook explain
# Just the hooks discovered from installed plugins
han hook list --plugin my-plugin
# Machine-readable
han hook list --plugin my-plugin --json
Output includes the hook command, its conditions (dirs_with, if_changed), and its event.
Run Hooks As Claude Code Would
han hook test executes hooks with a simulated Claude Code payload, which reproduces failures that only appear under a real event:
han hook test Stop
# Show the stdin payload each hook receives
han hook test Stop --payload
# Narrow to your plugin's command
han hook test --command my-plugin
View Cache
Inspect the hook cache:
ls -la .claude/cache/hooks/
There is no han cache clear. Force a re-run with han hook run my-plugin lint --no-cache, or delete the cache directory; Han rebuilds it on the next run.
Check Plugin Registration
Verify your plugin is registered:
# List all plugins
han plugin list
# Validate the plugin in the current directory
han plugin validate
There is no han plugin info. han plugin validate reports structural and manifest problems for the plugin you are standing in.
Debug Hook Failures
When hooks fail:
-
Check exit code: Non-zero means failure
han hook run my-plugin lint; echo "Exit: $?" -
Run command directly: Test the underlying command
npx eslint . -
Check environment: Verify required tools are installed
which npx npx eslint --version -
Check working directory: Ensure you're in the right place
pwd ls -la
Common Issues
Hook Not Running
Symptom: Hook skips unexpectedly
Causes:
- No files match
if_changedpatterns - Config file not found for
dirs_with - Cached result being used
Solution:
# Force re-run
han hook run my-plugin lint --no-cache --verbose
Skill Not Loading
Symptom: Claude doesn't use your skill
Causes:
- Invalid frontmatter YAML
- Missing
nameordescription - Plugin not installed correctly
Solution:
- Validate frontmatter syntax
- Re-install plugin
- Restart Claude Code session
MCP Server Connection Failed
Symptom: MCP tools unavailable
Causes:
- Server command fails to start
- Missing dependencies
- Invalid
.mcp.jsonsyntax
Solution:
# Test server manually
npx -y @your-org/mcp-server-your-service
# Check for errors in output
Testing Checklist
Before distribution, verify:
-
han plugin validate .passes - All hooks run successfully
- Hooks skip when conditions aren't met
- Skills have valid frontmatter
- Commands execute correctly
- MCP servers start (for integration plugins)
- Documentation is complete
- CHANGELOG is updated
Next Steps
- Distribution - Share your plugin