Add @executor-js/pi, a first-party Pi extension - #1961
Open
mangit955 wants to merge 1 commit into
Open
Conversation
Pi ships no MCP client, so connecting it to Executor meant trusting a third-party bridge with access to every configured integration. This adds an Executor-maintained extension instead. It registers Executor's core surface — executor_execute, executor_skills, and executor_resume — as native Pi tools and forwards each call over MCP, so Pi gets the same lazy discovery every other agent does and its context stays clear of individual tool schemas. Configuration is environment-only, never package config: EXECUTOR_MCP_URL plus EXECUTOR_API_KEY (hosted) or EXECUTOR_AUTH_TOKEN (local/desktop). /executor reports the resolved endpoint and checks the connection. Closes UsefulSoftwareCo#1957
mangit955
marked this pull request as ready for review
September 7, 2026 17:27
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses #1957.
Pi ships no MCP client, so
add-mcpdoes not apply to it and connecting Pi to Executor meant installing a third-party bridge — an unofficial adapter holding access to every integration you have configured. This adds an Executor-maintained extension instead.What it does
packages/hosts/piregisters Executor's core surface as native Pi tools and forwards each call over MCP:executor_execute— run JavaScript in the sandboxexecutor_skills— Executor's own docs, starting with the guide for writingexecutecodeexecutor_resume— resume an execution paused for approvalThat is the same small surface every other agent gets, so Pi's context stays clear of individual tool schemas and lazy discovery is preserved.
Configuration
Environment-only, deliberately. Pi installs this from npm, so a credential in package config would be a credential in every user's
node_modules— the issue called that out by name.EXECUTOR_MCP_URLEXECUTOR_API_KEYEXECUTOR_AUTH_TOKENEXECUTOR_API_KEYwins when both are set, matching the CLI's precedence inreadCliServerAuth./executorprints the resolved endpoint and the tools Executor actually serves, so an install can be checked before it is trusted.Design notes worth review
Startup never fails. Config resolution returns a result rather than throwing, and the MCP connection opens on first use — Pi has to start cleanly when Executor is down, misconfigured, or simply not running yet. A failed connect clears its memo so the next call retries, and a transport-level failure drops the session so an Executor restart is survivable without restarting Pi.
The tool set is a literal, not a mirror of
tools/list. That is what lets Pi start while Executor is unreachable.schema.test.tsasserts the registeredparametersagainst a real Executor MCP server, so drift fails CI rather than reaching users.elicitation_mode=modelis pinned onto the URL. Theresumeschema here is the model-mode shape (executionId+action+content). In browser mode the server registers aresumetakingexecutionIdalone, so a pasted?elicitation_mode=browserURL would leave us advertising parameters the server rejects. Unrelated query parameters are preserved.Errors are thrown, not returned. Pi's
AgentToolResulthas no error field — the harness marks a call failed exactly whenexecutethrows, and keeps only the message. So an MCPisErrorresult has to leave as a thrownErrorcarrying the server's text. Auth failures get a remedy specific to the variable the token came from, since a hosted API key and a local server token are refilled in different places. This is why.oxlintrc.jsoncscopes the throw/catch rules off for this package only: it sits on Pi's runtime boundary, where throwing is the protocol. The rules that keep our own failures typed stay on.Non-text content degrades rather than breaking. Pi accepts text and images only. Audio and resource blocks become a placeholder line; since Executor already precedes every binary block with a
File output: …line, the model still knows the file exists and what it is.Verification
format:check,lint,typecheck— cleanpackages/hosts/pi: 27 tests across 4 files passbun run --filter='@executor-js/pi' buildproduces the pathspublishConfig.exportsand thepimanifest point ate2e/scenarios/pi-extension.test.ts(selfhost) — packs and installs the package through Pi's own package manager, then drives it through Pi's own loader:/executor,executor_execute,executor_skills, and aexecutor_resumecall asserting the server accepts the advertised arguments. The whole user path with only the model left out.e2e/local/pi-extension.test.ts(local) — boots a realexecutor web, takes the token it prints, and follows the README exactly as a local user would.Both pass. The package is wired into
build:packages,publish-packages.ts, andsmoke-test-packed.ts, and a changeset is included.Not included
The issue also asks for Pi on the Integrations / "Connect an agent" screen. That is a separate change to the connect-card surface and I left it out to keep this reviewable; happy to follow up, or fold it in if you would rather it ship together.