@anthara/pi-claude

pi package that runs Claude Code plugins, skills, agents, settings and tools in pi

Packages

Package details

extension

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; /mcp shows 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 env block 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.

  • hooks run on the agent's own tool calls while a run started through Agent or Task lasts, and are released when it ends. PreToolUse, PostToolUse and PostToolUseFailure run; a Stop hook fires as SubagentStop when the run ends. Hooks on other events are not run, and an agent that a forked skill starts gets no hooks.
  • mcpServers lists 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.
  • permissionMode has 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 write or edit whose path, followed through links, lies in the main checkout is refused (a relative path is read against the worktree; the worktree itself, /tmp and 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 -C a folder outside the worktree, --git-dir, --work-tree, -c core.worktree, GIT_DIR= and GIT_WORK_TREE=; env -C <dir> and env --chdir=<dir> count as a cd for 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.