Skip to content

shaftoe/pi-coding-agent-action

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Repository files navigation

Pi Coding Agent Action

Codecov

A CI/CD action that integrates Pi coding agent with git hosting platform workflows. Works with GitHub, Codeberg, and self-hosted Forgejo instances — any platform that provides GitHub-compatible APIs and CI/CD environment variables.

Inspired by OpenCode's GitHub action.

Features

  • Issue assistance: Prefix any new issue description and/or any issue comment with /pi to have the agent analyze the issue, generate a report and/or create a new PR with the fix
  • PR assistance: Prefix any PR comment, review comment or review message with /pi to have the agent review the pull request and/or to apply further changes
  • Automated code reviews: Have Pi review every new pull request automatically
  • Add Pi to your own pipelines: (Optionally) generate prompt from upstream actions/workflows and have Pi do the work in background for you anywhere you like in your workflows
  • Minimal batteries included: Tries to follow Pi minimalistic phylosophy while providing a comfortable UX out of the box, e.g. pretty print of logs, auto replies to comments, and tools to interact efficiently with git and GitHub-compatible APIs.

Goal

If all you want is running Pi inside a CI/CD environment technically you don't need any custom action, something like

- uses: actions/setup-node@v6
- run: npm -g install @earendil-works/pi-coding-agent
- run: pi -p "do something useful for me"

might be just good enough and probably will always be the best fit for a pure "as minimalist as Pi" approach.

On the other hand that's true for almost everything which is offered by the Actions ecosystem, useful and popular Actions are mostly focused on providing a pleasant UX around the raw core functionality they provide.

This project goal is exactly that: to provide a short list of (opt-out) opinionated default features for interacting with and executing Pi agent sessions inside CI/CD environments compatible with GitHub API.

For all the rest you're free and encouraged to just configure the action environment as you would your local Pi instance, e.g. adding files to ~/.pi/agent/, environment variables, etc., and more generally to compose workflow pipelines around this action's inputs and outputs to fullfill your specific needs.

Refer to the official Pi documentation to learn how to tweak Pi to best fit your needs.

Disclaimer

Note

Codeberg/Forgejo compatibility should work but hasn't been tested yet.

Securing your workflows

Warning

Depending on the permissions assigned to your workflow you should consider restricting who's allowed to trigger it e.g. filtering for GitHub user name or role (if github.actor == '<my-user>').

Important

The develop and v2 branches are in constant development so if you don't want the bleeding edge you should pin to the latest release, e.g.

   uses: shaftoe/pi-coding-agent-action@v2.16.0

Usage

Interactive Workflows

  • Create a GitHub workflow which triggers when comments are added (e.g., issue_comment)
  • Filter by if to only run on the trigger phrase (e.g., contains(github.event.comment.body, '/pi'))
  • Add actions/setup-node as prerequisite step (Node version >= v22.x)
  • Finally, add shaftoe/pi-coding-agent-action

Example:

name: Pi Agent

on:
  issue_comment:
    types: [created]

permissions:
  contents: write
  pull-requests: write
  issues: write

jobs:
  pi-agent:
    if: contains(github.event.comment.body, '/pi')
    runs-on: ubuntu-latest
    steps:
      - name: Setup Node
        uses: actions/setup-node@v6
        with:
          node-version: 24

      - name: Run Pi agent
        uses: shaftoe/pi-coding-agent-action@v2
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          provider: my-provider
          model: some-model
          token: ${{ secrets.MODEL_API_KEY }}
          base_url: https://my-gateway.example.com/v1
          thinking_level: medium

Non-Interactive Workflows

You can use the prompt input to run the agent without requiring a comment trigger. This is useful for automated workflows like PR reviews, scheduled tasks, or prompts generated by a previous step:

- name: Run Pi agent with fixed prompt
  uses: shaftoe/pi-coding-agent-action@v2
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    provider: openai
    model: gpt-5.4
    token: ${{ secrets.OPENAI_API_KEY }}
    prompt: 'Review this pull request for security issues' # or e.g. ${{ steps.generate-prompt.outputs.prompt }}

When using the prompt input, the action still enriches the prompt with issue/PR context (title and description) if available in the workflow context.

Custom Extensions

You can load custom Pi extensions to add additional tools, custom tools, or modify agent behavior:

- name: Run Pi agent with extensions
  uses: shaftoe/pi-coding-agent-action@v2
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    provider: openai
    model: gpt-5.4
    token: ${{ secrets.OPENAI_API_KEY }}
    extensions: |
      npm:pi-subagents
      git:github.com/user/pi-custom-tools
      ./my-local-extension.ts

Supported extension sources:

  • npm packages: npm:package-name or npm:package@version
  • git repositories: git:github.com/user/repo (supports branches with #branch)
  • local files: Relative paths to .ts extension files

Custom Providers via models.json

The Pi SDK supports registering custom LLM providers (e.g., local servers, API gateways, OpenAI-compatible endpoints) through a models.json configuration file. By default the SDK looks for ~/.pi/agent/models.json. When the file doesn't exist, only the built-in providers are available — identical to the previous behavior.

See the Custom Provider documentation for the full schema reference.

Example: configure a custom provider in a previous workflow step

- name: Configure custom LLM provider
  run: |
    mkdir -p ~/.pi/agent
    cat > ~/.pi/agent/models.json << 'EOF'
    {
      "providers": {
        "my-llm": {
          "baseUrl": "https://api.example.com/v1",
          "apiKey": "${{ secrets.LLM_API_KEY }}",
          "models": [{
            "id": "my-model-v1",
            "name": "My Model V1",
            "api": "openai-chat",
            "cost": { "input": 0.001, "output": 0.002, "cacheRead": 0, "cacheWrite": 0 },
            "contextWindow": 128000,
            "maxTokens": 4096
          }]
        }
      }
    }
    EOF

- uses: shaftoe/pi-coding-agent-action@v2
  with:
    provider: my-llm
    model: my-model-v1
    token: ${{ secrets.LLM_API_KEY }}

Disabling Built-in Extensions

By default the action loads four built-in GitHub related tools (create_pull_request, update_pull_request, get_issue_or_pr_thread, get_pr_diff) to help Pi better interact with GitHub action environment without relying on external tools like gh nor need special skills setup for that. If you want Pi to use only your own custom extensions (or none at all), set load_builtin_extensions to false:

- name: Run Pi agent
  uses: shaftoe/pi-coding-agent-action@v2
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    provider: openai
    model: gpt-5.4
    token: ${{ secrets.OPENAI_API_KEY }}
    load_builtin_extensions: false
    extensions: |
      npm:my-custom-github-tools

Injecting Environment Variables

Pi extensions often require environment variables for authentication or configuration. Use the native env: step key to pass variables from your workflow's secrets or configuration into the Pi session:

- name: Run Pi agent with custom env vars
  uses: shaftoe/pi-coding-agent-action@v2
  env:
    MY_API_KEY: ${{ secrets.MY_API_KEY }}
    ANOTHER_SERVICE_TOKEN: ${{ secrets.ANOTHER_SERVICE_TOKEN }}
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    provider: openai
    model: gpt-5.4
    token: ${{ secrets.OPENAI_API_KEY }}

Since the action runs as a single Node.js process, these environment variables are available in process.env and accessible to all Pi extensions.

Token input

The token input is optional and the action auth could also be specified as environment variable instead, e.g:

- name: Run Pi agent with auth env var
  uses: shaftoe/pi-coding-agent-action@v2
  env:
    OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    provider: openai
    model: gpt-5.4

Examples in this documentation tend to favour input because is more consistent with GitHub environment variables/secrets and lets configure the LLM completely via the web admin interface without the need for patching workflow yaml files.

Using Outputs in Downstream Jobs

Use outputs.<job-id>.outputs.<name> to pass action outputs to another step or another job in the same workflow. For example, you can have Pi generate release notes in one job and then create a release in another:

jobs:
  pi-agent:
      # shortened for brevity...
      - name: Run Pi agent
        id: pi          # Required to access outputs from this step
        uses: shaftoe/pi-coding-agent-action@v2
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          provider: openai
          model: gpt-5.4
          token: ${{ secrets.OPENAI_API_KEY }}
          prompt: 'Generate release notes for the latest commit'

  publish:
    needs: pi-agent
    if: ${{ needs.pi-agent.outputs.success == 'true' }}
    runs-on: ubuntu-latest
    steps:
      - name: Log results
        run: |
          echo "Response: ${{ needs.pi-agent.outputs.response }}"
          echo "Cost: ${{ needs.pi-agent.outputs.cost }} USD"
          echo "Tokens: ${{ needs.pi-agent.outputs.input_tokens }} in / ${{ needs.pi-agent.outputs.output_tokens }} out"
          echo "Duration: ${{ needs.pi-agent.outputs.duration_seconds }}s"

      - name: Create GitHub release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          echo '${{ needs.pi-agent.outputs.response }}' > release-notes.md
          gh release create v1.0.0 --notes-file release-notes.md

Uploading Session HTML as Artifact

When export_session_html is enabled, the action writes a self-contained HTML file and exposes its path via the session_html_path output. It can be uploaded as a workflow artifact for example:

- uses: shaftoe/pi-coding-agent-action@v2
  id: pi
  with:
    export_session_html: true
    github_token: ${{ secrets.GITHUB_TOKEN }}
    provider: openai
    model: gpt-5.4
    token: ${{ secrets.OPENAI_API_KEY }}

- uses: actions/upload-artifact@v7
  if: ${{ steps.pi.outputs.session_html_path }}
  with:
    name: pi-session-html-${{ github.event.issue.number || github.event.pull_request.number || github.run_number }}
    path: ${{ steps.pi.outputs.session_html_path }}

Quick Start

Create a workflow file, e.g., .github/workflows/pi-agent.yml. See the interactive and non-interactive workflows in this repository to get started.

Inputs

Input Description Required Default
base_url Optional override for the provider base URL (e.g., to route traffic through a proxy or use an OpenAI-compatible gateway) No -
export_session_html Export the session as a self-contained HTML file No false
extensions Custom Pi extensions to load (one per line). Supports npm packages (npm:package-name), git repos (git:github.com/user/repo), or local file paths No -
github_token GitHub token for API access Yes -
load_builtin_extensions Whether to load built-in GitHub extensions (create_pull_request, update_pull_request, get_issue_or_pr_thread, get_pr_diff) No true
model Model to use (e.g., gpt-5.4, gpt-4o, gemini-2.5-pro) Yes -
prompt Optional prompt to send to the agent (skips comment extraction) No -
provider LLM provider (openai, google, anthropic, etc.) Yes -
thinking_level Model thinking level (off low medium
token Provider API token. Required for most providers, but can be omitted when using providers that support alternative auth mechanisms (e.g., google-vertex with Application Default Credentials) No -
trigger Trigger phrase used to invoke the action No /pi

Refer to Pi documentation for the current list of supported providers / models / etc.

Outputs

The action exposes the following outputs, which can be consumed by downstream steps or jobs:

Output Description Example
cost Cost of the invocation in USD (omitted if unavailable) 0.042
duration_seconds Wall-clock duration of agent execution in seconds 12.7
input_tokens Number of input tokens consumed (omitted if unavailable) 1500
output_tokens Number of output tokens generated (omitted if unavailable) 800
response The main agent response text (or error message on failure) Here is the fix for the bug...
session_html_path Path to the exported session HTML file (when export_session_html is enabled) /tmp/pi-session-html/session.html
success Whether the agent completed successfully (true / false) true

Warning

Tokens and cost outputs are only set when the underlying provider returns session statistics. They will be absent for providers that don't report token usage.

Custom Tools

The action extends Pi with four custom tools:

Tool Description
create_pull_request Creates a new pull request by detecting file changes, creating a branch, committing changes via GitHub API, and opening the PR. Supports dry_run mode for testing without actual PR creation.
get_issue_or_pr_thread Retrieves the full thread of an issue or pull request including title, body, state, labels, branch info (for PRs), all comments, and review comments (inline comments on specific lines of the diff) for PRs. Useful for understanding the full context before making changes.
get_pr_diff Fetches the diff of a pull request on demand. Useful when the agent needs to understand what changed in a PR, e.g. for code reviews or addressing review feedback. Supports configurable max_lines truncation (default: 1000).
update_pull_request Updates an existing pull request by pushing new commits to the PR branch and optionally updating the title and/or description. Supports dry_run mode for testing without actual modifications.

Tip

Set load_builtin_extensions input to false to disable custom tool auto loading.

Development

Prerequisites

  • Bun package manager
  • Node.js 24+

Validation

Before committing, run the following checks:

bun run validate

This runs:

  • Code formatting (Prettier)
  • Linting (ESLint)
  • Type checking (TypeScript)
  • Building

Testing

The project uses bun test for testing:

# Run all tests
bun test

# Run tests with coverage
bun run test:coverage

# Watch mode for development
bun run test:watch

# Run end to end tests (requires LLM to be setup)
bun run test:e2e

Project Guidelines

  • Follow the existing code style and conventions
  • Add tests for new functionality
  • Update documentation as needed
  • Use bun as the package manager (preferred over npm)
  • Run bun run validate before committing

Releasing

The project uses a developv2 branching strategy:

  • develop is the default branch. All PRs target it. The package.yml workflow auto-commits dist/ changes here.
  • v2 is the release branch. Merges into v2 trigger release.yml, which runs tests and semantic-release.

To cut a release:

git switch v2
git merge develop
git push origin v2

References

License

See LICENSE