cc-plugins
Bring your Claude Code plugins to pi without modification. cc-plugins reads CC-format plugin directories and registers their resources as native pi equivalents — commands, agents, skills, and hooks all work seamlessly.
Quick Start
Add a plugin source to your settings:
{ "ccPlugins": ["/path/to/cc-plugin"]}That’s it. Restart pi and your plugin’s commands, agents, skills, and hooks are available.
Source Types
Local paths
Point to plugin directories on your filesystem:
{ "ccPlugins": [ "/absolute/path/to/plugin", "./relative/to/project", "~/plugins/my-plugin" ]}Git pinned (planned)
Not yet implemented. Will fetch from a repository at a specific version, cached immutably:
{ "ccPlugins": [ "git:github.com/user/plugin@v1.0.0", "git:gitlab.com/team/plugin@2.1.3" ]}Git unpinned (planned)
Not yet implemented. Will fetch from a repository without a version tag, using TTL-based refresh:
{ "ccPlugins": [ "git:github.com/user/plugin" ]}Resource Mapping
Each Claude Code resource type maps to a pi equivalent:
commands/*.md: Registered as slash commands viaregisterCommand(). Invoke with/command-name.agents/*.md: Registered as agent commands. Spawns a pi subprocess with the agent’s prompt template.skills/*/SKILL.md: Registered as skill commands. Injected as a user message when invoked.hooks.json: Merged into pi’s hook system. Event names are mapped (see below), then hooks execute via pi’s EventBus.
Configuration
Simple format
In your settings.json, add a ccPlugins array:
{ "ccPlugins": [ "/path/to/local/plugin", "git:github.com/user/plugin@v1.0.0" ]}Advanced format
Create .pi/cc-plugins.json (project) or ~/.pi/agent/cc-plugins.json (global):
{ "sources": [ { "source": "git:github.com/user/plugin@v1.0.0", "include": ["commands/*", "skills/*"], "exclude": ["hooks.json"] }, "/path/to/local/plugin" ]}Use include and exclude glob patterns to filter which resources are loaded.
Hook Event Mapping
Claude Code hooks use different event names than pi. cc-plugins maps them automatically:
| CC Event | Pi Event | Notes |
|---|---|---|
PreToolUse | tool_call | Can block tool execution |
PostToolUse | tool_result | Observe only |
Stop | agent_end | Observe only |
Notification | — | Silently discarded |
SubagentStop | — | Silently discarded |
Hooks are merged at runtime. If your plugin defines a PreToolUse hook, it will fire on pi’s tool_call event.
Management
List loaded sources
/cc-plugins listShows all configured sources, their types (local, git pinned, git unpinned), and the resources loaded from each.
Refresh sources
/cc-plugins refreshCurrently requires a session restart to reload plugins. A future version will support hot-reload during development.
Caching
Currently, local sources are re-scanned from disk on every session start with no caching. Git sources are not yet supported (see roadmap).
Cache infrastructure exists internally (content hashing, TTL logic, mtime comparison) but is not yet wired up. The planned behavior:
| Source type | Cache behavior |
|---|---|
Git pinned (@version) | Clone once, cache immutably, never re-fetch |
| Git unpinned (no version) | Clone and cache, re-fetch after 1-hour TTL |
| Local paths | Cache scan results, invalidate on mtime change |
How It Works
At session_start, cc-plugins scans all configured sources. For each source, it:
- Resolves the path (local) or clones the repository (git — planned)
- Discovers resources (commands, agents, skills, hooks.json)
- Registers each resource via pi’s extension API
- Merges hooks into the global EventBus
Hooks are mapped from CC event names to pi event names, then registered with the same matchers and execution logic.
Hooks Integration
cc-plugins integrates with the hooks extension via the hooks:merge event bus. When a plugin provides a hooks.json, cc-plugins maps the CC event names to pi events and emits a hooks:merge event. The hooks extension picks these up at runtime and merges them into its active configuration — no file writes, no restarts needed beyond the initial session load.
This means CC-format hooks participate in the same execution pipeline as native pi hooks: matching, blocking (for tool_call), async background execution, and result delivery all work the same way.
Troubleshooting
Plugin not loading
- Check the path: Ensure the source path or git URL is correct.
- Check settings.json: Verify the
ccPluginsarray is valid JSON. - Run
/cc-plugins list: Confirm the source is registered and resources are loaded.
Hooks not firing
- Check the event mapping table: Your CC hook may use an event that doesn’t map to pi (like
Notification). - Check the hooks extension:
cc-pluginsrequires thehooksextension to be installed and active.
Name collision
If multiple plugins define the same command, agent, or skill, the last-registered one wins. Check /cc-plugins list to see which plugin is active. Collision warnings are shown at session start.