- Implemented context-hook.ts for handling session start events. - Created new-hook.ts for user prompt submission events. - Developed save-hook.ts for post tool use events. - Added summary-hook.ts for handling stop events. - Introduced worker.ts as a standalone background process for the SDK agent. - Each hook reads input from stdin, processes it, and handles errors gracefully.
7.6 KiB
Plugin Development Guide
This guide helps developers work with the claude-mem plugin structure during development.
Quick Start
1. Build the Plugin
# Build both CLI and hooks
npm run build
# Or build separately
npm run build:cli # Just the CLI
npm run build:hooks # Just the hooks
2. Test Hooks Locally
Test individual hooks by piping JSON input:
# Test context hook (SessionStart)
printf '{"session_id":"test-123","cwd":"/Users/you/project","source":"startup"}' | \
bun scripts/hooks/context-hook.js
# Test new hook (UserPromptSubmit)
printf '{"session_id":"test-123","cwd":"/Users/you/project","prompt":"help me code"}' | \
bun scripts/hooks/new-hook.js
# Test save hook (PostToolUse)
printf '{"session_id":"test-123","cwd":"/Users/you/project","tool_name":"Read","tool_input":{},"tool_output":{}}' | \
bun scripts/hooks/save-hook.js
# Test summary hook (Stop)
printf '{"session_id":"test-123","cwd":"/Users/you/project"}' | \
bun scripts/hooks/summary-hook.js
# Test worker (requires valid session ID in database)
bun scripts/hooks/worker.js 999
3. Test Worker with Plugin Root
Verify the new-hook correctly detects plugin mode:
# Without CLAUDE_PLUGIN_ROOT (traditional mode)
printf '{"session_id":"test-new","cwd":"/path","prompt":"test"}' | \
bun scripts/hooks/new-hook.js
# With CLAUDE_PLUGIN_ROOT (plugin mode)
CLAUDE_PLUGIN_ROOT=$(pwd) printf '{"session_id":"test-plugin","cwd":"/path","prompt":"test"}' | \
bun scripts/hooks/new-hook.js
In plugin mode, the new-hook will attempt to spawn bun ${CLAUDE_PLUGIN_ROOT}/scripts/hooks/worker.js.
In traditional mode, it will attempt to spawn claude-mem worker.
4. Test With No Input
Each hook should handle missing input gracefully:
echo '' | bun scripts/hooks/context-hook.js
# Output: No input provided - this script is designed to run as a Claude Code SessionStart hook
Local Plugin Testing
Option 1: Dev Marketplace (Recommended)
Create a development marketplace to test your plugin:
# Create marketplace structure
mkdir -p ~/dev-marketplace/.claude-plugin
# Create marketplace manifest
cat > ~/dev-marketplace/.claude-plugin/marketplace.json << 'EOF'
{
"name": "dev-marketplace",
"owner": {
"name": "Developer"
},
"plugins": [
{
"name": "claude-mem",
"source": "./claude-mem-plugin",
"description": "Persistent memory system for Claude Code"
}
]
}
EOF
# Symlink your working directory
ln -s /path/to/your/claude-mem ~/dev-marketplace/claude-mem-plugin
Then in Claude Code:
/plugin marketplace add /absolute/path/to/dev-marketplace
/plugin install claude-mem@dev-marketplace
Option 2: Direct Testing
Test the CLI commands directly:
# Build first
npm run build
# Test CLI commands
./dist/claude-mem.min.js --version
./dist/claude-mem.min.js status
./dist/claude-mem.min.js --help
Development Workflow
Making Changes to Hooks
- Edit TypeScript source in
src/hooks/orsrc/bin/hooks/ - Rebuild hooks:
npm run build:hooks - Test locally: Use echo piping method above
- Reinstall plugin (if testing in Claude Code):
/plugin uninstall claude-mem@dev-marketplace /plugin install claude-mem@dev-marketplace
Making Changes to CLI
- Edit TypeScript source in
src/ - Rebuild CLI:
npm run build:cli - Test directly:
./dist/claude-mem.min.js [command]
Making Changes to Commands
- Edit markdown files in
commands/ - No rebuild needed (commands are read directly)
- Reinstall plugin to pick up changes:
/plugin uninstall claude-mem@dev-marketplace /plugin install claude-mem@dev-marketplace
Debugging
Enable Verbose Logging
Set environment variables for more detailed output:
DEBUG=claude-mem:* bun scripts/hooks/context-hook.js
Check Hook Output
Hooks write to stdout/stderr. Capture output:
echo '{"session_id":"test","cwd":"/path"}' | \
bun scripts/hooks/context-hook.js 2>&1 | tee hook-output.log
Verify Plugin Root Variable
Test that ${CLAUDE_PLUGIN_ROOT} resolves correctly:
# Manually set it for testing
export CLAUDE_PLUGIN_ROOT=/path/to/your/plugin
echo '{"session_id":"test","cwd":"/path"}' | \
bun ${CLAUDE_PLUGIN_ROOT}/scripts/hooks/context-hook.js
Build System Details
Hook Build Process
The scripts/build-hooks.js script:
- Reads each entry point from
src/bin/hooks/ - Bundles with Bun build system
- Minifies output
- Adds shebang for direct execution
- Sets executable permissions
- Outputs to
scripts/hooks/
CLI Build Process
The scripts/build.js script:
- Bundles main CLI from
src/bin/cli.ts - Externalizes large dependencies
- Minifies output
- Adds shebang
- Sets executable permissions
- Outputs to
dist/claude-mem.min.js
Build Configuration
Both builds use similar Bun configuration:
- Target:
bunruntime - Minify:
true - External:
bun:sqlite(native module) - Define:
__DEFAULT_PACKAGE_VERSION__from package.json
Testing
Run Tests
bun test tests/
Test Database Operations
# Test hooks database
bun test tests/hooks-database-integration.test.ts
# Test session lifecycle
bun test tests/session-lifecycle.test.ts
Publishing
Pre-publish Checklist
- All tests pass:
bun test tests/ - Build succeeds:
npm run build - Version updated in
package.json - Changelog updated in
docs/CHANGELOG.md - Plugin.json version matches package.json
- Hooks tested locally
- CLI tested locally
Publish to npm
npm run publish:npm
This will:
- Run
prepublishOnlyscript (builds everything) - Publish to npm registry
- Include files listed in
package.json"files" array
Files Included in Package
The npm package includes:
dist/- Compiled CLIscripts/- Compiled hookscommands/- Slash command definitionshooks/- Hook configuration.claude-plugin/- Plugin metadatasrc/- TypeScript source (for reference)docs/- Documentation.mcp.json- MCP server configuration
Troubleshooting
Build Fails
Problem: bun: command not found
Solution: Install Bun from https://bun.sh
Problem: Build errors with external dependencies
Solution: Check that bun:sqlite is not bundled (should be external)
Hooks Don't Execute
Problem: Permission denied when executing hooks
Solution: Ensure scripts are executable: chmod +x scripts/hooks/*.js
Problem: Hooks exit silently Solution: Check error handling - hooks catch all errors and exit gracefully
Plugin Not Found
Problem: /plugin install can't find claude-mem
Solution:
- Verify marketplace is added:
/plugin marketplace list - Check marketplace manifest includes claude-mem
- Refresh marketplace:
/plugin marketplace refresh
Tips
- Use symlinks in dev marketplace for faster iteration
- Test hooks with edge cases (empty input, malformed JSON)
- Check file sizes after build to catch bloat
- Version everything together (CLI, hooks, plugin.json)
- Document breaking changes in CHANGELOG.md
Resources
- Plugin Structure Documentation
- Plugin Installation Guide
- Build Documentation
- Claude Code Plugins Docs
- Bun Documentation