Add Pi coding agent#67
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new pi coding-agent implementation to rix, wiring it into agent selection, CLI/workflow documentation, and cost parsing so it can be used alongside opencode and claude.
Changes:
- Introduces
PiAgent(npm-installed@earendil-works/pi-coding-agent) with JSON-mode invocation and cost parsing fromagent_end. - Extends agent parsing/selection to recognize
piacross config, CLI option help, and startup wiring. - Updates the reusable workflow and README to document
piand enforceagent-api-key-envwhenagent=piandagent-api-keyis provided.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Rix.Tests/PiAgentTests.cs | Adds unit tests for Pi installation behavior and invocation construction. |
| tests/Rix.Tests/PiAgentCostTests.cs | Adds unit tests for Pi cost parsing from agent_end JSON. |
| tests/Rix.Tests/JobConfigTests.cs | Extends job config tests to cover pi agent selection and model passthrough. |
| tests/Rix.Tests/AgentKindParserTests.cs | Adds coverage for parsing pi agent kind. |
| src/Rix/Startup.cs | Wires AgentKind.Pi to PiAgent in agent selection. |
| src/Rix/Cli/JobCommand.cs | Updates CLI help text to list pi as an available agent. |
| src/Rix/Agents/PiAgent.cs | Implements the new Pi agent: install, invocation, and cost parsing. |
| src/Rix/Agents/AgentKind.cs | Adds Pi to the enum and parser error message expectations. |
| README.md | Documents pi usage and credentials behavior. |
| .github/workflows/job.yml | Updates workflow inputs/help and enforces agent-api-key-env requirement for pi when a key is provided. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Wires the open-source Pi coding agent CLI (@earendil-works/pi-coding-agent) into the existing ICodingAgent abstraction alongside Claude and OpenCode, following the multi-provider model/API-key passthrough added for opencode. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ReadCost summed usage.cost.total from any message with that shape, not just assistant messages as documented — a non-assistant message with a numeric cost would have overcounted the run's total. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
agent_settled unconditionally follows agent_end and carries no payload, and JobRunner only ever inspects the final stdout line, so ParseCost's agent_end handling is correct but effectively unreachable in production; cost will report as 0, mirroring (more strongly) the known limitation OpenCodeAgent already documents for itself.
pi's real CLI doesn't fit the JSON-diagnostic/exit-1 pattern the existing opencode/claude tests rely on, so these two cases use the structural checks that actually match its behavior (confirmed by running the real CLI): no-credentials failures point at a real .md doc file the package ships rather than JSON, and an invalid key is swallowed into pi's own event stream as a successful run with no PRs rather than failing the process.
5dec517 to
2aaeb5d
Compare
| | `read-token` | Required. PAT with read access to the target repo; used to clone it during the agent run. | | ||
| | `write-token` | Required. PAT with `contents:write` + `pull-requests:write` on the target repo; used to push branches and open PRs. | | ||
| | `agent-api-key` | Optional. API key for the selected agent's model provider, exported as the env var named by `agent-api-key-env` (default `OPENCODE_API_KEY` for opencode, `ANTHROPIC_API_KEY` for claude). Not needed when leaving `model` unset, since opencode then picks its own free default model. | | ||
| | `agent-api-key` | Optional. API key for the selected agent's model provider, exported as the env var named by `agent-api-key-env` (default `OPENCODE_API_KEY` for opencode, `ANTHROPIC_API_KEY` for claude; `agent-api-key-env` is required for pi). Not needed when leaving `model` unset, since opencode then picks its own free default model. | |
There was a problem hiding this comment.
Fixed the wording in cc2243d — it now says agent-api-key-env must be set explicitly whenever agent-api-key is provided, matching the conditional phrasing already used in the pi paragraph above the table.
- ReadCost: drop the redundant type re-check (already gated by CostLine.Read's marker) and extract ReadAssistantCost as a guard-clause helper, matching OpenCodeAgent.ReadCost's shape. - Trim ParseCost's <remarks> to the load-bearing fact, dropping speculative framing. - Remove PiAgentCostTests' redundant non-assistant-message test, already covered by ParseCost_SumsAssistantMessageCosts_FromAgentEnd. - Consolidate the pi failure-mode explanation in rix-job-e2e.bats into the file header, replacing the duplicated inline comments with short pointers. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot review: the Secrets table read as if agent-api-key-env is always required for pi, when it's only required when agent-api-key is also set. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|



Summary
pias a thirdICodingAgentimplementation, alongsideclaudeandopencode, backed by the open-source Pi coding agent CLI (@earendil-works/pi-coding-agent).--modelis forwarded verbatim, and (since pi has no free default provider)agent-api-key-envis now required in the reusable workflow wheneveragent: piis used withagent-api-key.agent_endJSON event by summingusage.cost.totalacross all assistant messages — but note pi's true last stdout line is always a payload-freeagent_settledevent, so under the current one-line-only architecture this reliably reports$0, a stronger version of the same known limitationOpenCodeAgentalready documents for itself.Stacked on #64 (live e2e job harness), rebased there after review feedback that this needed real integration coverage rather than only unit tests.
Test plan
dotnet buildsucceedsdotnet test— 201/201 passing, including newPiAgentTests/PiAgentCostTeststests/e2e/rix-job-e2e.bats, run locally against the realpiCLI (confirmed passing):.mddoc path the package ships (not JSON — pi has no structured error protocol for this path, unlike claude/opencode)