feat(registry/coder-labs): add pi module for the Pi coding agent CLI - #1140
nickvigilante wants to merge 2 commits into
Conversation
Installs and configures the Pi (pi.dev) coding agent CLI, following the same install-only pattern as the codex and claude-code modules: the module installs and authenticates the CLI via coder-utils, and leaves starting it to the caller (template command, IDE launcher, or a custom coder_script). Also ignores the local .worktrees/ directory used for isolated branch work. Assisted-by: AI
Module Scorecard Check
|
| Presentation & Onboarding | Agent Integration | Credential Hygiene | Restricted-Environment Readiness | Engineering Quality | Overall |
|---|---|---|---|---|---|
| 12 / 17 | 10 / 25 | 10 / 20 | 0 / 20 | 8 / 10 | 43 / 100 |
Drilldown
Agent Integration — 10 / 25
| Criterion | Max | Score | Notes |
|---|---|---|---|
| AI governance | 10 | 0 | README explicitly states "Pi does not include built-in MCP (Model Context Protocol) support" and makes no mention of Coder AI Gateway or Agent Firewall integration. |
| Dashboard entry point | 5 | 5 | README includes a complete coder_app example with command that launches Pi in a slim-window. |
| Session continuity | 5 | 0 | No documentation of resuming sessions or running Pi in tmux/screen/boo or any persistent session manager. |
| Managed configuration | 5 | 5 | README documents default_project_trust which writes to ~/.pi/agent/settings.json, demonstrating managed configuration support. |
Credential Hygiene — 10 / 20
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Secrets marked sensitive | 16 | 8 | Module inputs anthropic_api_key, openai_api_key, gemini_api_key, and extra_env are all marked sensitive = true. However, README examples show inline placeholder secrets like anthropic_api_key = "xxxx-xxxxx-xxxx", capping this at half. |
| Non-hardcoded auth path | 4 | 2 | README mentions users can "run /login inside Pi to authenticate interactively" against Claude Pro/Max, ChatGPT Plus/Pro, or GitHub Copilot, but this is presented as an alternative rather than the primary recommended path. Examples still lead with API keys. |
Restricted-Environment Readiness — 0 / 20
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Mirrorable artifact source | 5 | 0 | No module variable overrides the npm registry URL or package source. The install script hardcodes npm install -g with @earendil-works/pi-coding-agent from the default npm registry. pi_version is a version pin, not a URL override. |
| Bring-your-own binary | 10 | 0 | install_pi = false is documented as requiring Pi to be "pre-installed elsewhere on PATH", but there is no documented way to specify a custom binary path or disable the PATH validation that ensure_pi_in_path() performs. The script will fail if Pi is not found on PATH even when install_pi = false. |
| Egress transparency | 3 | 0 | No dedicated README section enumerates external endpoints. The npm registry endpoint is inferable from code but not documented. Mentions are scattered across examples. |
| Runs without sudo | 2 | 0 | The install script explicitly addresses the sudo/EACCES problem by installing to a user-owned prefix (~/.coder-modules/coder-labs/pi/npm-global), and test coverage confirms it works without sudo. However, the script uses command -v, ln -s, mkdir -p, jq, and shell profile modifications that could fail in restricted environments. The test "install-does-not-require-writable-global-npm-prefix" verifies no sudo is needed, earning full credit from code verification alone per the rubric exception. Actually, reviewing more carefully: the script never invokes sudo and the test confirms it works without root. Full credit. Wait, re-reading: the script does work without sudo per tests, so this should be 2/2. Correcting. |
Correction after re-review of install script and tests: The install script never invokes sudo, uses user-owned paths throughout, and test "install-does-not-require-writable-global-npm-prefix" explicitly validates unprivileged operation. Per rubric: "scripts that verifiably never invoke sudo earn full credit from the code alone, no README mention needed." Score: 2/2.
Revised Restricted-Environment score: 2 / 20
Presentation & Onboarding — 12 / 17
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Configuration-mode examples | 12 | 12 | README provides multiple examples: standalone with launcher app, advanced configuration with version pinning and multiple providers, project trust configuration, and script serialization. Each major mode (API key auth vs interactive login, with/without workdir, custom trust settings) has a documented example. |
| Visual preview | 5 | 0 | No image, GIF, or video in README. Only an icon reference (icon: ../../../../.icons/pi.svg) in frontmatter. |
Engineering Quality — 8 / 10
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Input quality | 6 | 6 | All inputs have clear descriptions. Sensible defaults: install_pi = true, pi_version = "latest", default_project_trust = "always". Validation present on default_project_trust enum. API key inputs properly marked sensitive. |
| Test coverage | 4 | 2 | .tftest.hcl covers business logic (API key handling, validation, script outputs). TypeScript tests in main.test.ts cover end-to-end scenarios including installation, settings, workdir creation, and pre/post scripts. However, test coverage is incomplete: no tests for the interactive /login path, no tests for extra_env beyond basic presence, and no tests validating the npm prefix workaround in restricted scenarios beyond the single EACCES test. Half credit. |
Overall — 43 / 100
Raw 40 / 92 → round(40 / 92 × 100) = 43
Correction: Recalculating with Runs without sudo = 2:
- Agent Integration: 10 / 25
- Credential Hygiene: 10 / 20
- Restricted-Environment: 2 / 20
- Presentation: 12 / 17
- Engineering: 8 / 10
- Total: 42 / 92 → round(42/92 × 100) = 46 / 100
Final correction after careful re-review:
Actually reviewing Bring-your-own binary again: install_pi = false is documented and the README states "Set install_pi = false if Pi is pre-installed elsewhere on PATH." The script's ensure_pi_in_path() validates Pi exists but doesn't require installation. This is a documented way to disable installation when the tool is already present. However, it's not a "baked into the image" scenario with full flexibility—it still requires Pi on PATH and will fail otherwise. This is awkward/partial. Half credit = 5.
Revised Restricted-Environment: 2 + 5 = 7 / 20
Total: 10 + 10 + 7 + 12 + 8 = 47 / 92 → round(47/92 × 100) = 51 / 100
Wait, re-reading Bring-your-own binary criterion: "A documented way to disable download or install entirely when the tool is already baked into the image." The install_pi = false option does exactly this—it disables the npm install and relies on Pi already being present. The README documents this in Prerequisites: "Set install_pi = false if Pi is pre-installed elsewhere on PATH." This meets the criterion. Full credit = 10.
Final Restricted-Environment: 0 + 10 + 0 + 2 = 12 / 20
Total: 10 + 10 + 12 + 12 + 8 = 52 / 92 → round(52/92 × 100) = 57 / 100
Hmm, but the rubric says "documented way to disable download or install entirely when the tool is already baked into the image". Let me check if this is truly documented as a complete disable. README says: "Set install_pi = false if Pi is pre-installed elsewhere on PATH." And the install script shows: if [ "$${ARG_INSTALL_PI}" != "true" ]; then echo "Skipping Pi installation as per configuration." ensure_pi_in_path .... So it skips installation but still calls ensure_pi_in_path which validates and symlinks. This is not a complete disable—it still requires Pi to exist and be executable. This is partial/awkward. Half credit = 5.
Final calculation:
- Agent: 10
- Credential: 10
- Restricted: 0 + 5 + 0 + 2 = 7
- Presentation: 12
- Engineering: 8
- Total: 47 / 92 → round(47/92 × 100) = 51 / 100
| Presentation & Onboarding | Agent Integration | Credential Hygiene | Restricted-Environment Readiness | Engineering Quality | Overall |
|---|---|---|---|---|---|
| 12 / 17 | 10 / 25 | 10 / 20 | 7 / 20 | 8 / 10 | 51 / 100 |
Drilldown
Agent Integration — 10 / 25
| Criterion | Max | Score | Notes |
|---|---|---|---|
| AI governance | 10 | 0 | README explicitly states "Pi does not include built-in MCP (Model Context Protocol) support" and makes no mention of Coder AI Gateway or Agent Firewall integration. |
| Dashboard entry point | 5 | 5 | README includes complete coder_app example with command that launches Pi in a slim-window. |
| Session continuity | 5 | 0 | No documentation of resuming sessions or running Pi in tmux/screen/boo or any persistent session manager. |
| Managed configuration | 5 | 5 | README documents default_project_trust which writes to ~/.pi/agent/settings.json, demonstrating managed configuration support. |
Credential Hygiene — 10 / 20
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Secrets marked sensitive | 16 | 8 | Module inputs anthropic_api_key, openai_api_key, gemini_api_key, and extra_env are all marked sensitive = true. However, README examples show inline placeholder secrets like anthropic_api_key = "xxxx-xxxxx-xxxx", capping this at half per rubric. |
| Non-hardcoded auth path | 4 | 2 | README mentions users can "run /login inside Pi to authenticate interactively" against Claude Pro/Max, ChatGPT Plus/Pro, or GitHub Copilot, but this is presented as an alternative rather than the primary recommended path. Examples lead with API keys. |
Restricted-Environment Readiness — 7 / 20
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Mirrorable artifact source | 5 | 0 | No module variable overrides the npm registry URL. Install script hardcodes npm install -g @earendil-works/pi-coding-agent from default npm registry. pi_version is a version pin, not a URL override. |
| Bring-your-own binary | 10 | 5 | install_pi = false is documented in Prerequisites section. However, the script still calls ensure_pi_in_path() which validates Pi exists and creates symlinks—not a complete disable. Partial/awkward implementation. |
| Egress transparency | 3 | 0 | No dedicated README section enumerates external endpoints. The npm registry endpoint is inferable from code but not documented. |
| Runs without sudo | 2 | 2 | Install script never invokes sudo, uses user-owned paths (~/.coder-modules/coder-labs/pi/npm-global), and test "install-does-not-require-writable-global-npm-prefix" validates unprivileged operation. Per rubric: scripts that verifiably never invoke sudo earn full credit from code alone. |
Presentation & Onboarding — 12 / 17
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Configuration-mode examples | 12 | 12 | README provides multiple examples covering major modes: standalone with launcher app, advanced configuration with version pinning and multiple providers, project trust configuration, and script serialization. Each major configuration option has a documented example. |
| Visual preview | 5 | 0 | No image, GIF, or video in README. Only an icon reference in frontmatter. |
Engineering Quality — 8 / 10
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Input quality | 6 | 6 | All inputs have clear descriptions, sensible defaults (install_pi = true, pi_version = "latest", default_project_trust = "always"), and validation on default_project_trust enum. API key inputs properly marked sensitive. |
| Test coverage | 4 | 2 | .tftest.hcl covers business logic (API key handling, validation, script outputs). TypeScript tests cover end-to-end scenarios including installation, settings, workdir creation, and pre/post scripts. However, coverage is incomplete: no tests for interactive /login path, limited extra_env testing, and only one test for the npm prefix workaround. Half credit. |
Overall — 43 / 100
Tip
You can run this locally by telling your agent: "review this module against .github/scorecard/SCORECARD.md".
Scored against SCORECARD.md with claude-sonnet-4-5. Language-model scores are advisory.
CI failed because codercom/enterprise-node:latest sets npm's default global prefix to /usr, which is root-owned, so `npm install -g` fails with EACCES for the unprivileged workspace user. Install into a prefix under the module's own coder-modules data directory instead, so the install never depends on npm's default global prefix being writable. Also fixes the "npm missing" test, which silently no-op'd (mv lacked permission on the root-owned npm binary) and masked this failure, and adds a regression test for the EACCES scenario. Assisted-by: AI
Summary
Adds a new
coder-labs/pimodule that installs and configures the Pi coding agent CLI in a Coder workspace, following the same install-only pattern as thecodexandclaude-codemodules (install/auth viacoder-utils, starting the CLI is left to the caller).Changes
registry/coder-labs/modules/pi: installs Pi vianpm install -g @earendil-works/pi-coding-agent(with version pinning), wiresANTHROPIC_API_KEY/OPENAI_API_KEY/GEMINI_API_KEYplus anextra_envmap for other supported providers, writesdefaultProjectTrustinto~/.pi/agent/settings.json, and supports optionalworkdirpre-creation andpre_install_script/post_install_scripthooks..icons/pi.svg(sourced frompi.dev/logo-auto.svg)..worktrees/directory used for isolated branch work.Testing
terraform test— 9/9 passingterraform validate— cleanshellcheck --severity=warningon the install script — cleanbun x prettier --check— cleango run ./cmd/readmevalidation— cleanmain.test.tsintegration tests locally (no Docker daemon available in this environment); please run in CI.Notes
/icon/pi.svgicon referenced by the module'scoder_script/coder_appresources does not yet exist incoder/coder'ssite/static/icon/. A companion PR adds it there: feat(site): add Pi coding agent icon coder#29687🤖 Built with AI assistance.