@wbline/pi-acp-jetbrain
ACP adapter for the pi coding agent (JetBrains IDEs primary host)
Package details
Install @wbline/pi-acp-jetbrain from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@wbline/pi-acp-jetbrain- Package
@wbline/pi-acp-jetbrain- Version
0.4.0- Published
- Oct 8, 2026
- Downloads
- 1,741/mo · 54/wk
- Author
- wongbin
- License
- MIT
- Types
- extension
- Size
- 854.3 KB
- Dependencies
- 2 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-acp-jetbrain
An Agent Client Protocol (ACP) adapter for the pi coding agent. JetBrains IntelliJ is the primary host. Other ACP clients work with partial coverage.
The adapter runs as an ACP server over stdio. Each ACP session starts one pi --mode rpc subprocess. The adapter translates messages between the client and pi.
npm package: @wbline/pi-acp-jetbrain (see the version badge for the current release). GitHub Actions publishes each
release with signed provenance over npm OIDC; no npm token is needed on CI.
Fork notice. This package is a fork of the upstream ryan-brosas/pi-acp-jetbrain project, licensed under the MIT License with the original copyright held by Sergii Kozak (2025). See LICENSE. All fork-local changes and maintenance are published by
@wblineunder the same MIT terms.
Coverage
The adapter covers the session surface: session/new, session/prompt, session/cancel, session/list,
session/load, session/fork, session/resume, session/close, session/delete, session/mode. Pi keeps its own
session files. The adapter keeps a small map at ~/.pi/pi-acp/session-map.json so a load can reattach to the stored
session.
Assistant text streams as agent_message_chunk. Reasoning streams as agent_thought_chunk when the provider sends it. Tool runs map to tool_call and tool_call_update events.
Edit events carry a file location when pi reports a path. The adapter resolves relative paths against the session working directory. For text edits it finds the changed line from one unique match and reports a structured diff.
Each session starts with a pi startup block. Set quietStartup: true in pi settings to hide it.
After each settled turn the adapter reports token use and cost from pi session statistics. It sends the data on the unstable usage field.
Text input requests use the unstable ACP elicitation API when the client has it. Requests that fit permissions route through ACP permissions. An editor request shows a cancellation notice because elicitation forms hold primitive fields only.
The model selector works through a mapping from pi models to ACP provider info. Pi keeps provider credentials outside the RPC surface.
Slash commands load file-based prompts from pi and a set of built-ins: /compact, /export, /session, /name, /queue, /changelog, /steering, /follow-up. Skills appear as /skill:<name> when enabled in pi settings.
The /reload command reloads both the MCP bridge (IDE tools) and pi components (extensions, skills, prompts, themes, context files).
The local tree carries pi developer tooling: 9 prompt commands, 101 skill files (91 leaves in 10 packs), and 12 format templates under .pi/. These checks run in the development tree and skip on clean CI checkouts.
JetBrains IDE bridge
IntelliJ sends its built-in MCP server descriptor with each chat. The adapter exposes those IDE tools to pi as ide_<server>_<tool> extension tools.
The bridge opens a direct MCP-over-SSE client against http://127.0.0.1:<IJ_MCP_SERVER_PORT>/sse when the descriptor carries that port. It starts the stdio child only when that endpoint is unreachable.
Two allowlists guard the IDE tools. The IDE side reads idea_mcp_allowed_tools from ~/.jetbrains/acp.json. An omitted key means AllowAll in the installed build. The adapter side deny-lists execute_tool and every xdebug_* name. Set PI_ACP_IDE_EXTRA_TOOLS with a comma separated list of remote names to re-allow tools you reviewed.
The session catalog never changes. After you edit IntelliJ MCP settings or the allowlist, open a new chat.
Install
Node.js 20 or newer. The pi executable on your PATH.
Install it as a Pi package to activate the bundled bridge extension:
pi install npm:@wbline/pi-acp-jetbrain
Pi records the package in ~/.pi/agent/settings.json and enables its declared extension automatically. Installing only with npm install -g provides the executable but does not activate Pi package resources.
Install the pi-acp command globally when you want it directly on your PATH:
npm install -g @wbline/pi-acp-jetbrain
The package name is @wbline/pi-acp-jetbrain. The installed command is pi-acp-jetbrain.
Register the adapter in ~/.jetbrains/acp.json:
{
"agent_servers": {
"pi-acp-jetbrain": {
"command": "pi-acp-jetbrain",
"args": [],
"env": {}
}
}
}
npx works too. Pin the version so a later start cannot fetch a different release:
Replace <version> with the current release (see the badge):
{
"agent_servers": {
"pi-acp-jetbrain": {
"command": "npx",
"args": ["-y", "@wbline/pi-acp-jetbrain@<version>"],
"env": {}
}
}
}
From source:
npm install
npm run build
Point the entry to dist/index.js:
{
"agent_servers": {
"pi-acp-jetbrain": {
"command": "node",
"args": ["/path/to/pi-acp-jetbrain/dist/index.js"],
"env": {}
}
}
}
A development profile with a conservative tool subset:
{
"agent_servers": {
"pi-acp-jetbrain": {
"command": "/path/to/pi-acp-jetbrain/dist/index.js",
"args": [],
"env": {
"PI_ACP_PI_COMMAND": "/path/to/pi",
"PI_ACP_DEBUG_BRIDGE": "1"
},
"idea_mcp_allowed_tools": [
"search_symbol",
"get_symbol_info",
"analyze_calls",
"search_text",
"search_regex",
"get_file_problems",
"lint_files",
"build_project",
"execute_run_configuration",
"git_status",
"get_repositories",
"get_project_modules",
"get_project_dependencies",
"list_directory_tree",
"read_file",
"search_file",
"open_file_in_editor",
"get_all_open_file_paths",
"skill_search"
]
}
}
}
idea_mcp_allowed_tools acts as a deny-all mask plus the named tools. Add tools as you need them.
Environment variables
| Variable | Effect |
|---|---|
PI_ACP_PI_COMMAND |
Path to the pi executable. Default: pi. |
PI_ACP_DEBUG_BRIDGE=1 |
Log the sanitized session/new MCP descriptor to stderr. IntelliJ writes that stderr into idea.log. |
PI_ACP_ENABLE_EMBEDDED_CONTEXT=true |
Advertise embeddedContext support. |
PI_ACP_ENFORCE_IDE_INSPECT=0 |
Disable the inspection gate that runs after each turn. |
PI_ACP_ENFORCE_IDE_KTS=0|1 |
Repo KTS scripts: 0 never runs them; 1 runs them without consent. Unset: asks via a permission request on first use and remembers "Always allow". |
PI_ACP_IDE_MODE=off|prefer|required |
IntelliJ-first coding mode for the session. Default: prefer (degrades to native tools when the IDE is unavailable; off is the explicit opt-out). See the IntelliJ-first coding mode section. |
PI_ACP_IDE_INSPECT_DIR |
Move inspection reports out of the project tree. |
PI_ACP_SESSION_MAP |
Override the session map path. Default: ~/.pi/pi-acp/session-map.json. |
PI_ACP_IDE_EXTRA_TOOLS |
Re-allow deny-listed IDE tools. Comma separated remote names. |
Plan/Build mode
To use the session/mode feature to switch between plan and build modes, install an extra pi plugin:
pi install npm:@janvitos/pi-plan-build
Once installed, plan/build mode is available in JetBrains IDE chats for project planning and building.
IntelliJ-first coding mode
Set PI_ACP_IDE_MODE to control how the session uses IntelliJ for normal coding work. Pi still generates every implementation; IntelliJ opens, reads, searches, applies, renames, reformats, and validates.
offopts out entirely: IDE tools are exposed alongside native tools, nothing is removed, no extra prompt guidance.prefer(default) removes the nativeread,edit,write,grep,find, andlstools from the active set when the required IDE capabilities register. If the IDE bridge degrades, those tools come back and the session gets an explicit fallback notice.requiredremoves the same native tools immediately and keeps them removed while the IDE bridge is missing or disconnected. The task is blocked for as long as the outage lasts; the adapter retries the IPC connection with capped exponential backoff and the session returns to active automatically once the bridge is healthy again.
Required capabilities: read_file, open_file_in_editor, apply_patch, create_new_file, one search tool, and one inspection tool. Tool names are discovered from the live catalog, never guessed.
In active modes, mutations run through IntelliJ and open the affected files: existing files open before apply_patch, created and moved files open after. Patch targets and path arguments are confined to the ACP project root; paths outside it are rejected, including symlink escapes. Structured path fields in search and inspection results are checked against the project root. In prefer, results naming files outside the root are diagnosed on the result; in required, they are rejected. Unstructured result text is passed through unchanged: generic text scanning is not a safe discriminator, so per-tool structured adapters remain the boundary (an upstream limitation).
Bash stays available in prefer for Git, tests, builds, and diagnostics. Unrestricted bash can still mutate files, so this mode is policy enforcement for normal coding tools, not a filesystem sandbox. Do not rely on it as a security boundary.
In prefer and required with an active catalog, direct Fabric/Schema file mutations (schema.commit, pi.write, pi.edit inside fabric_exec) are blocked before execution by a heuristic tool_call gate (a comment-stripping text scan: whitespace-obfuscated direct calls are caught, but aliased or indirectly-dispatched calls can bypass it — the provenance audit below is the backstop). Mutations must flow through the IDE tools (ide_idea_apply_patch, ide_idea_create_new_file, rename, reformat), which open affected files and confine patch/path arguments to the project root. Read-only Fabric code (pi.read, pi.grep, IDE tool calls) is unaffected. This narrows the extension-tool bypass of the active-set filter; Bash remains an intentional, documented exception.
The IDE-reported project root must resolve to the same directory as the session working directory (case-insensitive on Windows; symlinked roots compared via realpath). On a mismatch, the mode fails closed — prefer degrades to native_fallback, required to required_unavailable — with a diagnostic, because the mutation fence and the git-based provenance audit would otherwise normalize the same file against different roots.
A second layer runs after each turn: the extension reports paths applied by successful IDE mutation tools over the authenticated IPC (mutations_applied), and the adapter compares those against files that became dirty during the turn (git status relative to a turn-start baseline, merged with turn-touched tool paths; native edit/write paths count as covered only while the IDE is not driving the active set). Failed and cancelled turns still run this audit — mutations made before a failure are real and must not be washed out by the next turn's baseline — while the inspection summary stays end-turn-only. Files that changed without an IDE mutation event are surfaced as Mutation provenance violations in the chat (one combined post-turn block with the inspection summary, repo-relative report paths) and recorded under PromptResponse._meta.piAcp.mutationViolations. When git status exceeds the 200-file bound, both gates append a truncation note instead of silently under-reporting. Disable with PI_ACP_ENFORCE_IDE_MUTATIONS=0. Deleted files and files committed mid-turn by an external auto-commit watcher are not detected by this layer (same git-status semantics as the inspection gate).
When the mode can degrade or fail
The mode is a per-session adaptation implemented by this adapter, not a persistent IDE setting. Its enforcement is driven by a live capability probe over the IDE bridge, so it can degrade or fail in the following situations:
- Bridge missing / IPC disconnects: enforcement is stateful (
active,native_fallback,required_unavailable). Inprefer, a lost or missing bridge drops the session tonative_fallbackand the native tools come back, with an explicit notice. Inrequired, the session becomesrequired_unavailableand the task is treated as blocked while the outage lasts. The extension retries the IPC connection with capped exponential backoff (reset on a healthy registration) and both states recover automatically — tools re-filtered, native tools withdrawn — once the bridge re-registers. - Capability probe misses: the active mode depends on registering all required capabilities (
read_file,open_file_in_editor,apply_patch,create_new_file, one search tool, one inspection tool). If any required capability is missing — for example after an IDE update that renames or removes an MCP tool —preferfalls back andrequiredgoes unavailable. Tool names are discovered from the live catalog, never guessed, so an IDE-side rename can silently break the probe. - Config changes need a new chat: the bridge and capability probe are established at session start. After editing
idea_mcp_allowed_tools, thePI_ACP_IDE_MODEvalue, or IDE MCP settings, open a new chat; an already-open session does not reconnect or re-evaluate its mode. - Invalid value fails closed: any
PI_ACP_IDE_MODEvalue other thanoff/prefer/required(e.g. a typo) is treated asrequiredand fails closed, which can block tasks rather than safely landing back on thepreferdefault. - Not a security sandbox: mode enforcement covers normal coding tools only. Bash stays available (in
prefer) and can still mutate files; the provenance gate reports violations without rolling back.
Set the variable for the adapter process, for example in ~/.jetbrains/acp.json:
{
"agent_servers": {
"pi-acp-jetbrain": {
"command": "/path/to/pi-acp-jetbrain/dist/index.js",
"env": { "PI_ACP_IDE_MODE": "prefer", "PI_ACP_PI_COMMAND": "/path/to/pi" }
}
}
}
Authentication
The adapter advertises terminal auth metadata. Run this command for interactive provider login:
pi-acp-jetbrain --terminal-login
ACP clients can start the same command from their auth UI.
Development
npm install
npm run dev # run from src with tsx
npm run build
npm run lint
npm run test
npm run typecheck
npm run format
npm run smoke # core stdio smoke tests
npm run smoke:full # full matrix; run this before a release
node scripts/check.mjs
Code layout:
src/acp/holds the ACP server, session logic, and ACP↔pi translation (acp/translate/,acp/commands/).src/mcp/holds the ACP-side MCP bridge and its transports (stdio, SSE, IPC).src/pi-extension/holds the extension bundled into pi;src/policy/holds coding policy shared by both sides.src/pi/holds the pi subprocess wrapper and its RPC/session/settings wrappers.
Limitations
Trust boundary
The adapter trusts its ACP host. The host supplies the session working directory and client-provided MCP descriptors; stdio MCP servers named in a descriptor are spawned with the adapter's process environment in that working directory. Run the adapter only with hosts and MCP configurations you control. Do not expose it as a service to untrusted clients or place unnecessary secrets in the adapter environment.
PI_ACP_IDE_MODE=prefer|required is policy enforcement for normal coding tools, not a
filesystem sandbox: unrestricted Bash stays available, and the post-turn gates report
violations without rolling back changes. See the
When the mode can degrade or fail section for the
conditions under which the mode can silently fall back or block a session.
The adapter does not expose ACP filesystem or terminal delegation. Pi reads files and runs commands locally.
providers/set and providers/disable return a method-not-found error. Pi configures providers outside the RPC surface.
The ACP plan surface stays unwired. The installed SDK does not define a plan method.
Debugger tools register only while an IDE debug session is live. Start a debug session and open a new chat to see them.
After you rebuild the adapter, open a new chat. Node keeps the old files loaded, and IntelliJ reuses running agent processes.
Post-turn gates depend on git
The mutation provenance audit inside the post-turn gates compares git status snapshots, so it
only works in git checkouts. Outside a git repository the audit cannot run; the adapter emits a
one-time note per session when this happens instead of staying silent. The opt-out environment
variables (PI_ACP_ENFORCE_IDE_MUTATIONS, PI_ACP_ENFORCE_IDE_INSPECT) are unaffected.
Slash command routing is three-layered
Built-in commands (/compact, /session, /name, /steering, /follow-up, /changelog,
/export, /autocompact, /reload) are handled adapter-side in src/acp/commands/builtin-commands.ts
and never reach pi. File-based commands from .pi/ markdown are expanded inside
session.prompt(). Everything else is forwarded to pi, which resolves its own commands and
extension commands (for example /acp-reload, registered by the bundled bridge extension).
When a command misbehaves, check the matching layer first.
Trademarks
JetBrains, IntelliJ IDEA, and WebStorm are trademarks of JetBrains s.r.o. This project is an independent, community-maintained adapter and is not affiliated with, endorsed by, or sponsored by JetBrains. Trademarks belong to their respective owners; they are used here only for describing the tools the adapter interoperates with.
License
MIT. See LICENSE.