Skip to content

feat: add pi coding agent extension package with MCP adapter integration#42

Open
pikujs wants to merge 3 commits into
agent-sh:mainfrom
pikujs:feat/pi-extension-package
Open

feat: add pi coding agent extension package with MCP adapter integration#42
pikujs wants to merge 3 commits into
agent-sh:mainfrom
pikujs:feat/pi-extension-package

Conversation

@pikujs

@pikujs pikujs commented Jul 5, 2026

Copy link
Copy Markdown

Summary

Add a self-contained pi coding agent extension package to the existing computer-use-linux repository. Users can now run pi install npm:@agent-sh/computer-use-linux and get Linux desktop control tools through pi-mcp-adapter's MCP proxy — without maintaining a separate pi-specific skill or duplicating tool definitions.

Key Changes

New: Pi extension (pi/extension/index.ts)

  • Auto-discovers the computer-use-linux binary on first load (checks COMPUTER_USE_LINUX_BIN env var → npm-bundled binary → $PATH)
  • On session_start, writes/merges the MCP server entry into ~/.pi/agent/mcp.json — the config file that pi-mcp-adapter reads
  • If the binary or pi-mcp-adapter is missing, notifies the user with actionable instructions
  • No npm dependency on pi-mcp-adapter — it's a documented prerequisite, keeping the package clean for non-pi users

Refactored: Skill (skills/computer-use-linux/SKILL.md)

  • Made the skill host-agnostic: removed "when Hermes needs" from the description, generalized the "Configure" section with a generic MCP config snippet
  • Moved Hermes-specific setup to references/hermes-setup.md
  • Added Pi-specific setup guide at references/pi-setup.md
  • Core Procedure, When to Use, and Pitfalls sections unchanged — they were already MCP-generic

Updated: Package metadata (package.json)

  • Added pi manifest pointing to the extension and skill
  • Added pi-package keyword for pi package registry discovery
  • Added pi/ and references/ to the npm tarball files list

Updated: README

  • Added "Pi Coding Agent" install and usage section

Design Decisions

Concern Decision
Why not register pi-specific tools? Would need a duplicate pi skill → 2 skills to maintain. Instead, reuse the existing MCP skill via pi-mcp-adapter's proxy tool.
Why no pi-mcp-adapter npm dependency? Regular npm install users (Hermes, Claude, etc.) shouldn't pull pi-only packages. It's documented as a prerequisite.
How is the binary discovered? Lazy, idempotent lookup: env var → npm postinstall artifact → PATH. Never reinstalls, only discovers.
How does the MCP config work? Extension writes to ~/.pi/agent/mcp.json — the same file pi-mcp-adapter reads. Merge strategy: reads existing config, updates only the computer-use-linux entry.

Verification

  • Binary auto-discovery works (tested with cargo install on PATH)
  • MCP config is written correctly to ~/.pi/agent/mcp.json
  • All 18 MCP tools are exposed through the MCP gateway
  • computer_use_linux_doctor, computer_use_linux_list_windows, computer_use_linux_click verified end-to-end
  • AT-SPI accessibility tree extraction works (tested with Firefox, Telegram Desktop on Hyprland)
  • npm pack --dry-run includes all new files
  • Skill loads correctly and shows host-specific references

Notes

  • This is a non-breaking addition — existing Hermes, Claude Desktop, Codex, and npm usage is unaffected
  • The .gitignore change (.agent-shell/ and .agent-docs) is a pre-existing local modification, unrelated to this feature
  • AT-SPI accessibility requires toolkit-accessibility = true (runnable via gsettings or Hyprland exec-once)

Fixes: N/A — feature addition

Add a self-contained pi coding agent extension package to the
existing computer-use-linux repository so users can install it
with `pi install npm:@agent-sh/computer-use-linux` and gain
Linux desktop control through pi-mcp-adapter's MCP proxy tool.

Key changes:

- Create pi/extension/index.ts: TypeScript extension that
  auto-discovers the computer-use-linux binary (env var → npm
  bundled → PATH) and writes the MCP server config to
  ~/.pi/agent/mcp.json for pi-mcp-adapter to consume.

- Refactor skills/computer-use-linux/SKILL.md: Make the skill
  generic and host-agnostic. Move Hermes-specific install/config
  steps to references/hermes-setup.md and add a new Pi setup
  guide at references/pi-setup.md. The core Procedure, When to
  Use, and Pitfalls sections remain unchanged — they were already
  MCP-generic.

- Update package.json: Add `pi` manifest key pointing to the
  extension and skill, `pi-package` keyword, and include the
  new pi/ and references/ directories in the published package.
  No npm dependency on pi-mcp-adapter — it remains a documented
  prerequisite to avoid pulling pi-only packages for regular
  npm install users.

- Update README.md: Add Pi Coding Agent install section after
  the existing Hermes Agent section.
@pikujs pikujs requested a review from avifenesh as a code owner July 5, 2026 19:58

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for the Pi coding agent, including a new TypeScript extension to auto-register the computer-use-linux binary as an MCP server, updated package configuration, and restructured documentation with host-specific setup guides for Hermes and Pi. The review feedback highlights two important robustness improvements in the new extension: validating the parsed JSON structure in readMcpConfig to prevent runtime crashes or configuration corruption, and wrapping synchronous filesystem operations in a try-catch block to handle potential write errors gracefully.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread pi/extension/index.ts Outdated
Comment on lines +111 to +118
function readMcpConfig(path: string): McpConfig {
try {
const raw = readFileSync(path, "utf-8");
return JSON.parse(raw) as McpConfig;
} catch {
return {};
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If the mcp.json config file is empty, corrupted, or contains a non-object value (such as null or an array), JSON.parse can return a value that is not a plain object. This leads to two issues:

  1. If it returns null, accessing config.mcpServers will throw a TypeError at runtime, crashing the extension.
  2. If it returns an array, spreading it with { ...config } will convert it into an object with numeric keys (e.g., { "0": ..., "mcpServers": ... }), corrupting the configuration file.

We should validate that the parsed JSON is a non-null, non-array object before returning it.

function readMcpConfig(path: string): McpConfig {
	try {
		const raw = readFileSync(path, "utf-8");
		const parsed = JSON.parse(raw);
		if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
			return parsed as McpConfig;
		}
		return {};
	} catch {
		return {};
	}
}

Comment thread pi/extension/index.ts Outdated
Comment on lines +170 to +179
const configPath = getPiAgentMcpConfigPath();
const changed = ensureServerEntry(configPath, binaryPath);

if (changed && ctx.hasUI) {
ctx.ui.notify?.(
`${PACKAGE_NAME}: MCP server configured at ${configPath}. ` +
"Run /reload if pi-mcp-adapter is already installed.",
"info",
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The call to ensureServerEntry performs synchronous filesystem operations (readFileSync, mkdirSync, writeFileSync). If any of these operations fail (e.g., due to permission issues, a read-only filesystem, or disk full), an unhandled exception will be thrown inside the async session_start event handler. This can lead to unhandled promise rejections or crash the Pi agent process.

We should wrap the configuration update in a try-catch block to handle filesystem errors gracefully and notify the user of the failure.

		const configPath = getPiAgentMcpConfigPath();
		try {
			const changed = ensureServerEntry(configPath, binaryPath);
			if (changed && ctx.hasUI) {
				ctx.ui.notify?.(
					PACKAGE_NAME + ": MCP server configured at " + configPath + ". " +
						"Run /reload if pi-mcp-adapter is already installed.",
					"info",
				);
			}
		} catch (err) {
			ctx.ui.notify?.(
				PACKAGE_NAME + ": Failed to update MCP config at " + configPath + ": " + (err instanceof Error ? err.message : String(err)),
				"warning",
			);
		}

- Add isRecord() type guard to validate JSON.parse result in
  readMcpConfig() before casting to McpConfig
- Wrap mkdirSync/writeFileSync in try-catch in writeMcpConfig()
  to handle permission errors gracefully
- Log write failures to console instead of crashing

@avifenesh avifenesh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an auto review done by revuto.


I found one remaining correctness issue in the new Pi extension config path.

Comment thread pi/extension/index.ts Outdated
args: ["mcp"],
};

writeMcpConfig(configPath, { ...config, mcpServers: servers });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an auto review done by revuto.


writeMcpConfig now catches mkdirSync/writeFileSync failures and only logs them, but ensureServerEntry still returns true unconditionally after this call. That makes the session handler notify that the MCP server was configured even when mcp.json was not written (permission denied, read-only FS, disk full, etc.), leaving pi-mcp-adapter with no computer-use-linux entry and no visible desktop tools. Please propagate the write failure (or have writeMcpConfig return a success boolean) so the extension can warn the user instead of reporting a successful configuration.

@avifenesh

Copy link
Copy Markdown
Collaborator

Hey @pikujs, thanks for this. I re-checked the current head and there are two things I think we should fix before merging:

  1. The config write path can still report success even if mcp.json was not written. writeMcpConfig catches write failures and only logs them, while ensureServerEntry returns true, so Pi can show “configured” with no usable MCP entry. Please propagate that failure and also validate that mcpServers itself is a plain object before mutating it.
  2. The Pi docs examples should use the adapter-discovered/prefixed tool names, or tell users to search first. With the current default pi-mcp-adapter prefixing, mcp({ tool: "doctor" }) / mcp({ tool: "list_windows" }) do not resolve; the verified names are like computer_use_linux_doctor and computer_use_linux_list_windows.

Once those are fixed this should be in much better shape.

Error handling hardening (per review audit):
- Add accessSync(constants.X_OK) to PATH search so non-executable
  files on PATH are skipped instead of failing at spawn time
- Log a warning when mcp.json contains valid JSON that is not a
  plain object (e.g. array), instead of silently returning null
- Wrap session_start async handler in try-catch to prevent
  unhandled promise rejections from unexpected errors
- Return null from readMcpConfig when file exists but can't be
  read/parsed, so ensureServerEntry knows not to overwrite it

Doc fixes:
- Fix pi-setup.md and README.md examples to use correct
  server-prefixed tool names (computer_use_linux_doctor)
- Add mcp({ server: ... }) listing pattern to both docs
@pikujs

pikujs commented Jul 5, 2026

Copy link
Copy Markdown
Author

I checked your reviews and hardenned the exception handling

@avifenesh avifenesh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an auto review done by revuto.


I found one remaining failure-mode issue in the Pi extension registration path.

Comment thread pi/extension/index.ts

// Write/update the MCP config that pi-mcp-adapter reads
const configPath = getPiAgentMcpConfigPath();
const changed = ensureServerEntry(configPath, binaryPath);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an auto review done by revuto.


ensureServerEntry now returns false for both “already up to date” and “could not read/write the config” (see the config === null and write-error paths above). Because the session handler only notifies when changed is true, a corrupt/unreadable mcp.json or a failed write leaves pi-mcp-adapter without the computer-use-linux server entry but shows no UI warning as long as the mcp tool itself is installed. Please distinguish the no-op and failure cases (or surface a warning from the failure path) so users get actionable feedback when registration did not actually happen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants