@anthara/pi-claude
pi package that runs Claude Code plugins, skills, agents, settings and tools in pi
Package details
Install @anthara/pi-claude from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@anthara/pi-claude- Package
@anthara/pi-claude- Version
0.2.0- Published
- Nov 9, 2026
- Downloads
- 243/mo · 243/wk
- Author
- sapanparikh18
- License
- Apache-2.0
- Types
- extension
- Size
- 2.1 MB
- Dependencies
- 2 dependencies · 5 peers
Pi manifest JSON
{
"extensions": [
"./dist/extensions/settings-env",
"./dist/extensions/hooks",
"./dist/extensions"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@anthara/pi-claude
A pi package that runs Claude Code configuration in pi: Claude Code plugins (installed with /plugin, or by Claude Code), their skills and agents, Claude's tool names (Agent, Task, AskUserQuestion, Skill, TodoWrite, ToolSearch), and the env block of Claude's settings.json.
pi install npm:@anthara/pi-claude
Claude configuration is read from CLAUDE_CONFIG_DIR, else ~/.claude. The package is self-contained: it needs no other pi package.
If another pi package also registers Agent, AskUserQuestion, TodoWrite or Skill, pi refuses to start, whichever package is listed first, and names both extension files (Tool "TodoWrite" conflicts with …); remove one of the two with pi remove. A package that registers pi-code's tools (subagent, question, todo, slash_command) does the same jobs under other names, so the session warns once, naming the package and the pi remove command that removes it.
Not carried over from pi-code
The package replaces pi-code, and these pi-code features have no replacement here: --add-dir and the add-dir memory loading, the context usage readout, the status line, session titles, git checkpoints, /goal, /init, plan mode, pi-code's own memory (Anthara's memory is Fabric, through the plugin's MCP server), desktop notifications, settings flags, the thinking controls and the version floor check.
Plugins
/plugin add <github:owner/repo[@ref] | git URL[@ref] | local git checkout>, /plugin update <name>[@ref], /plugin remove <name>, /plugin enable <name>, /plugin disable <name> and /plugin list. Installs go under the pi agent folder, pi-claude/plugins/<name>/<full commit SHA>/, recorded with their source, ref and enabled state in pi-claude/plugins/index.json; the package never writes into the Claude config folder. A ref is a tag or a full SHA, never a branch; without one the latest tag is used. .claude-plugin/plugin.json is optional (the plugin is then named after its repository or folder), and top-level fields Claude does not define are reported when the plugin is added. Changes apply after /reload or in the next session.
Plugins Claude Code installed in the Claude config folder load read-only, enabled as Claude Code's enabledPlugins says; /plugin list shows them, and removing, updating, enabling or disabling one is refused. When a plugin installed with /plugin has the same name, it wins and the session says the other one does not load.
Settings env
The env block of the user settings.json is applied as pi loads the package. A project's .claude/settings.json and .claude/settings.local.json (at the repository root) are applied only once the project is trusted. pi itself asks about trust only for .pi/ and .agents/skills content, so the package asks once more for a project that ships Claude Code configuration (.mcp.json, .claude/settings*.json, .claude/commands, skills, agents or output-styles) and keeps the answer in pi's own trust.json. A session with no UI does not trust such a project until that answer exists.
Skills load from enabled plugins (skills/, the directories the manifest's skills names, or a root SKILL.md), from <Claude config>/skills and from each .claude/skills between the working folder and the repository root. /<plugin>:<skill> <args>, /skill:<name> <args> and the Skill tool expand the skill the way Claude does ($ARGUMENTS, $0, named arguments:, ${CLAUDE_SKILL_DIR} and the other ${CLAUDE_*} variables, @file inside the project, and !`cmd` spans with a 2-minute limit). Frontmatter that Claude accepts and pi's YAML rejects still loads. A project skill's spans run only in a project you trusted; in any other they are replaced by a line saying they were not run, and the skill is not listed to the model. disableSkillShellExecution: true in your settings refuses every span.
A settings file may not set a variable that decides where files go or how pi or Claude Code run: HOME, TMPDIR, TMP, TEMP, CLAUDE_CONFIG_DIR, PI_CODING_AGENT_DIR, Claude's tracing switches, and anything starting with CLAUDE_CODE_, XDG_, PI_CODE_ or PI_CLAUDE_. A host that starts pi can reserve more names by listing them, comma separated, in PI_CLAUDE_RESERVED_ENV_KEYS. Such a key is never applied; the session warns once, naming the key and the file, never the value.
Output styles, plugin executables and a plugin's main agent
/output-style lists Claude's built-in styles (Concise, Explanatory, Learning, Proactive), enabled plugins' styles as <plugin>:<name>, <Claude config>/output-styles and, in a trusted project, .claude/output-styles. The choice is kept per project under the pi agent folder (pi-claude/output-style.json), never in the project. A style replaces pi's default instructions unless its frontmatter sets keep-coding-instructions: true.
Files in an enabled plugin's bin/ run by bare name from the Bash tool. They are added after your own PATH, for that tool only, so a plugin cannot shadow a system command and hooks and MCP servers do not see them.
A plugin's settings.json (or the manifest's settings) agent runs the main session as that plugin's agent: its prompt, tools and model. An agent in your own Claude settings wins. Other keys in a plugin's settings are ignored, and the session says so once.
MCP servers' headersHelper
An http MCP server's headersHelper runs for an enabled plugin's server, for an agent's inline server and, in a project you trusted, for the project's .mcp.json server; an untrusted project's servers are not connected at all. The command runs through /bin/sh in the project folder with CLAUDE_CODE_MCP_SERVER_NAME, CLAUDE_CODE_MCP_SERVER_URL (without user info, query or fragment, and without a path that names a variable), CLAUDE_PROJECT_DIR and, for a plugin's server, CLAUDE_PLUGIN_ROOT and CLAUDE_PLUGIN_DATA. Variables whose names contain TOKEN, SECRET, PASSWORD, PASSWD, CREDENTIAL, API_KEY, PRIVATE_KEY or AUTH are removed from its environment, and so are the reserved names above except HOME, TMPDIR, TMP, TEMP and XDG_*. It has 10 seconds, and must print one JSON object of header names and text values, which replace static headers of the same name. It runs once when the session starts to learn the header names, then again on every connect and reconnect, with nothing cached; the values are kept out of every file, notice and log. ${user_config.*} in the command is refused, naming the server.
When the helper fails, times out or prints something else as the session starts, the server connects with its static headers and the session says so once, naming the server and never the output. Limits:
- A helper that fails on a later connect or reconnect fails that connect, because pi runs the header command itself;
/mcpshows the error, which names pi-claude's runner and never a header value. - The helper is not rerun after a 401 or 403 answer: pi gives a package nothing to hook there.
- ws and sse servers stay disabled, with or without a
headersHelper. - pi resolves each header on its own, so the helper runs once per header it printed on each connect; headers that must come from the same run, such as a signature over a timestamp, can disagree.
- A trusted project's settings
envblock does not reach the helper, as it does not reach hooks.
Agents' hooks and MCP servers
Your own agents (<Claude config>/agents and the pi agent folder's agents/) and, in a project you trusted, its .claude/agents can declare hooks and mcpServers. Plugin agents ignore both, and permissionMode and initialPrompt too, as Claude Code's plugin agents do; the session says so once.
hooksrun on the agent's own tool calls while a run started throughAgentorTasklasts, and are released when it ends.PreToolUse,PostToolUseandPostToolUseFailurerun; aStophook fires asSubagentStopwhen the run ends. Hooks on other events are not run, and an agent that a forked skill starts gets no hooks.mcpServerslists server names and inline{ <name>: <config> }servers. A name gives the agent the session's server of that name, through the session's connection. An inline stdio or http server connects when the agent starts, is offered to that agent alone, and disconnects when the run ends. A server that cannot connect leaves the agent running without it, and the session warns once, naming the agent and the server.- Calls to an agent's inline MCP servers happen inside the agent's own session, so neither the session's hooks nor the agent's own hooks see them.
permissionModehas no effect in pi; the session says so once per agent.
Worktree agents
An agent with isolation: worktree runs in its own git worktree under the pi agent folder (pi-claude/worktrees/<run id>), and every one of its bash commands starts there. Claude Code's three checks keep it out of the main checkout, the repository git names as the top level of your working folder:
- a
writeoreditwhose path, followed through links, lies in the main checkout is refused (a relative path is read against the worktree; the worktree itself,/tmpand other folders are allowed); - a bash command that changes into the main checkout and then runs git is refused;
- git pointed elsewhere is refused:
git -Ca folder outside the worktree,--git-dir,--work-tree,-c core.worktree,GIT_DIR=andGIT_WORK_TREE=;env -C <dir>andenv --chdir=<dir>count as acdfor the git that follows.
A refused call is blocked after the session's PreToolUse hooks have seen it, and the agent gets the reason, which names its worktree. Limits:
| Limit | Why |
|---|---|
Writes a shell command makes, such as cp, mv, > or a script, are not tracked |
Claude Code documents the same limit; only the command's text is read |
| git reached through a variable, an alias, a function or a script is not seen, and a commit message that names one of the refused forms is refused | The checks read the command's text |
| PostToolUse and PostToolUseFailure do not fire for a refused call | pi emits no tool result for a call that is blocked, as for one a hook blocks |
A worktree agent gets no powershell; one a forked skill starts, or one granted Write, Edit or Bash that the session has not activated, gets no write, edit or bash either |
Those calls would not reach the session, where the checks run, and powershell would not start in the worktree |
Hooks
Hooks from the user's settings.json, a trusted project's .claude/settings*.json, enabled plugins and skill frontmatter run as in Claude Code. Handler types: command, http, prompt and agent (a read-only sub-agent that answers {"ok": ...}). An mcp_tool handler is reported once and not run, because pi gives a hook no way to call a tool on an MCP server it connects.
Supported events, with the pi event or announcement each rides:
| Claude event | Rides |
|---|---|
PreToolUse |
tool_call |
PostToolUse |
tool_result |
PostToolUseFailure |
tool_result |
UserPromptSubmit |
input |
SessionStart |
session_start |
Setup |
setup |
FileChanged |
file-changed |
PostCompact |
session_compact |
Stop |
agent_end |
PreCompact |
session_before_compact |
SessionEnd |
session_shutdown |
SubagentStart |
subagent-starting |
SubagentStop |
subagent-stopped |
Notification |
idle_prompt |
PostModelSwitch |
model_select |
InstructionsLoaded |
anthara.pi-claude:instructions-loaded |
UserPromptExpansion |
anthara.pi-claude:prompt-expanded |
PostToolBatch |
turn_end |
StopFailure |
agent_end |
WorktreeCreate |
anthara.pi-claude:worktree |
WorktreeRemove |
anthara.pi-claude:worktree |
Setup runs once, at the start of a session that began with --init or --maintenance (the matcher and the payload's trigger are init or maintenance). Only command hooks run, and their answers are discarded. Put the flag after the prompt, because pi gives the token after a flag to the flag as its value: anthara -p "<prompt>" --init.
FileChanged watches each |-separated name of the matcher as a literal file name in the working directory, and an add, change or unlink fires the hook with file_path and event. A hook's watchPaths (absolute paths) replaces the extra watch list, and its systemMessage is shown; the event cannot block. No watcher is opened when no FileChanged hook exists, and a project's hooks are watched only in a trusted project.
SubagentStart runs before the child's first prompt and its additionalContext is added to that prompt. UserPromptExpansion, WorktreeCreate and WorktreeRemove are notifications: a hook cannot block or replace the expansion or the worktree.
Events this package does not support are listed with their reasons under Not supported.
Not supported
This section lists every Claude Code behaviour that pi-claude does not provide, with its reason. A row that names a feature described elsewhere in this README links to it. A difference that is not listed here is a bug.
Hook events
A plugin or settings file that declares one of these events is warned about once per session, naming the event and where it came from.
| Claude event | Reason |
|---|---|
PermissionRequest |
pi has no permission dialog, so there is no request to answer |
PermissionDenied |
pi has no permission classifier, so no call is ever denied that way |
MessageDisplay |
pi has no event at the moment a message is shown that a hook could answer |
TaskCreated |
the package offers no task tools; TodoWrite lists are not tasks |
TaskCompleted |
the package offers no task tools; TodoWrite lists are not tasks |
TeammateIdle |
the package has no agent teams |
ConfigChange |
pi does not watch settings files while a session runs |
CwdChanged |
a pi session keeps the working folder it started in |
DirectoryAdded |
the package has no command that adds a working directory |
PreModelSwitch |
pi announces a model only after it has been switched, so nothing can run before |
Elicitation |
pi's MCP client does not hand an extension the questions a server asks |
ElicitationResult |
pi's MCP client does not hand an extension the questions a server asks |
Hook handlers and behaviour
| Behaviour | Reason |
|---|---|
mcp_tool handler |
pi gives a hook no way to call a tool on an MCP server it connects |
FileChanged for a folder event with no file name |
Node's folder watcher sometimes gives no file name, so every watched file in that folder is checked again, and a change can be reported for a file that did not change |
A UserPromptExpansion, WorktreeCreate or WorktreeRemove hook that blocks or replaces the expansion or the worktree |
the package reports these after they happen, so a hook can observe them and cannot stop them |
Setup handlers other than command, and their answers |
Setup runs at the start of a session, and only command handlers run there |
MCP servers
| Behaviour | Reason |
|---|---|
sse and ws servers |
pi's MCP client connects only stdio and http servers, so the server is registered disabled, named with its transport, and the session says so once |
Retrying a headersHelper after a 401 or 403 |
pi gives an extension no hook on an authentication failure |
The other headersHelper limits are listed in MCP servers' headersHelper.
Marketplace sources
A marketplace entry can name an npm package, a zip archive or a command that prints a folder. Each limit below applies to one of them, or to all of them.
| Behaviour | Reason |
|---|---|
| npm install scripts run, and npm dependencies are installed | pi-claude runs no plugin code while a plugin installs, so the npm fetch runs with scripts off and installs nothing |
| A plugin's Node dependencies are installed from its lockfile | Claude Code's separate lockfile step is not run, for the same reason: installing a plugin runs no code |
npm packages named as an npm: alias, a file: path or folder, a git address, a tarball on github.com, gitlab.com, bitbucket.org or git.sr.ht, an http tarball, or a link with a user name or password |
each would fetch from somewhere other than the npm registry, or read a local path, and the entry is refused naming the plugin |
| A zip's links and special files | a link could point outside the plugin once it is installed, so the whole archive is refused rather than the link kept |
headers and headersHelper on an archive download |
an archive entry has no field for them, so a download sends no credentials, and a private archive cannot be installed |
| Archive and npm sizes above 256 MiB or 20,000 entries | the caps are the ones Claude Code documents for command sources, applied to every source; Claude's larger limits (512 MiB per file, 1 GiB in total, 100,000 entries) are not used |
"mode": "link" on a command entry |
the install is a copy named by its content, and a linked folder could change under it without an update |
| A command with a character other than printable ASCII, tab or line feed | the consent question must show exactly the text that runs, and no other character can hide part of it |
/plugin update of a git marketplace install |
the install records the marketplace entry it came from, and /plugin update does not re-read it; marketplace update, then remove and install <name>@<marketplace>, replaces it |
/plugin update of a marketplace install does not install a dependency that a newer entry added |
the update stages only the plugin itself |
Worktree agents
| Behaviour | Reason |
|---|---|
Writes a shell command makes, such as cp, mv, > or a script |
Claude Code documents the same limit; only the command's text is read |
The other limits of isolation: worktree are listed in Worktree agents.
Agents
| Behaviour | Reason |
|---|---|
permissionMode |
pi never asks for approval, so there is no mode to set |
| An agent's hooks on events other than its tool calls and its end | a run's hooks are scoped to its own tool calls and to its end |
| An agent's inline MCP calls seen by the session's hooks, or by the agent's own hooks | the calls happen inside the agent's own session |
| A forked skill's agent gets hooks | a forked skill has no calling tool call to scope its hooks to |
initialPrompt that starts with a slash command, in -p mode, is expanded as that command |
the text is prepended to the prompt, so the combined text no longer starts with the command |
Agent memory |
memory is Fabric-backed, and pi-claude writes no memory files; without Fabric's tools the agent runs without memory and the session says so once |
Skills and commands
| Behaviour | Reason |
|---|---|
allowed-tools |
pi never asks for approval, so pre-approving a tool changes nothing; every tool stays callable |
disallowed-tools with a scoped entry such as Bash(rm:*) |
pi-claude does not match arguments, so it refuses the whole tool rather than let a refused call through |
model of a command or skill run through the Skill tool |
a model switch inside a running turn would change the model under the turn's parallel calls, so only a typed command applies it |
Tools and sessions
| Behaviour | Reason |
|---|---|
| Deferred loading of MCP tools for ToolSearch | the launcher sets ENABLE_TOOL_SEARCH=false, so every tool is loaded up front; a keyword query ranks loaded tools and marks them as already available |
| The TodoWrite panel shows every item | pi draws at most ten lines of a widget, so the panel shows eight rows and says how many are hidden; the list itself is complete |
| A TodoWrite list saved by a session before this version | the saved entries are from an earlier todo tool, so the list is not restored |
Background sub-agents continue after /new, /resume, /fork or /reload |
a run cannot move into a new session, and Claude Code does not document what happens to one; the run is stopped, and a notice names it so it can be rerun |
Licence
Apache-2.0. Parts are adapted from pi-code (MIT); see NOTICE.