@gotgenes/pi-github-tools6.1.0
Pi extension providing deterministic GitHub CI, release, and issue tools.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
@gotgenes/pi-github-tools
Pi extension providing deterministic GitHub CI, release, and issue tools.
Replaces ad-hoc gh CLI polling with structured tools that have exponential backoff, progress streaming, and structured success/timeout returns.
Install
pi install npm:@gotgenes/pi-github-tools
Alternatively, add it to your Pi settings (~/.pi/agent/settings.json):
{
"packages": ["npm:@gotgenes/pi-github-tools"]
}
Prerequisites
- GitHub CLI (
gh) installed and authenticated (gh auth login) - Git on
PATH, for theissue_closecommit-SHA check - Node.js ≥ 22
Tools
CI tools
ci_find
Wait for a GitHub Actions run matching a specific commit SHA to appear. Uses exponential backoff (5 s base, 30 s cap) until the run appears or the timeout expires.
| Parameter | Type | Required | Description |
|---|---|---|---|
workflow |
string | yes | Workflow filename without extension (e.g., "ci" for ci.yml) |
expected_sha |
string | yes | Full 40-char SHA of the commit |
timeout |
number | no | Seconds to wait (default: 120) |
Returns run_id, url, status, sha, title, and job list on success.
Returns a structured timeout message (not an error) if the run does not appear.
ci_watch
Poll a GitHub Actions run by run ID until it completes or times out.
Streams compact job-level progress lines (e.g., [2/5] deploy — in_progress (120s)).
| Parameter | Type | Required | Description |
|---|---|---|---|
workflow |
string | yes | Workflow filename without extension |
run_id |
number | yes | Run ID from ci_find |
timeout |
number | no | Seconds to wait (default: 300) |
ci_list
List recent GitHub Actions runs for a workflow.
Useful for diagnostics without constructing gh invocations.
| Parameter | Type | Required | Description |
|---|---|---|---|
workflow |
string | yes | Workflow filename without extension |
limit |
number | no | Number of runs to return (default: 5) |
Transient-failure retry
Every read-only gh call these tools make — ci_find, ci_watch, and ci_list — retries a transient failure up to three times, waiting 1 s, 4 s, then 9 s.
The retry count and backoff curve match @octokit/plugin-retry's defaults.
Retried: HTTP 5xx, GitHub's no server is currently available GraphQL error, and transport errors (connection reset, unexpected EOF, i/o timeout, TLS handshake timeout).
Not retried: any 4xx, including rate limiting — retrying those is useless or harmful.
Mutations (gh pr merge, gh issue close) are never retried automatically.
For a merge, the verification described above is what makes a retry decision safe.
In a polling tool the backoff counts against the call's timeout, so retries cannot silently extend the wait the caller asked for.
Issue tools
issue_close
Close a GitHub issue with an optional comment.
Before closing, each lowercase word-bounded hex token of 7 to 40 characters in the comment must resolve with git rev-parse --verify <token>^{commit} in the local checkout.
If any does not, the tool refuses, naming the tokens, and nothing is closed or posted.
The check does not fetch and does not test ancestry.
Set skip_sha_validation only to cite a foreign commit or a non-commit hash — correct a typo instead.
| Parameter | Type | Required | Description |
|---|---|---|---|
issue_number |
number | yes | The issue number to close |
comment |
string | no | Comment to add when closing |
reason |
string | no | "completed" (default) or "not_planned" |
skip_sha_validation |
boolean | no | Skip local SHA resolution (default refuses) |
Usage example
A typical CI + release flow using these tools:
1. Push changes to a branch and create a PR.
2. Use ci_find with the pushed SHA to locate the CI run.
3. Use ci_watch to wait for the CI run to complete.
4. Merge the PR.
5. Dispatch the repository's release workflow for the shipped package.
6. Use ci_find and ci_watch with that workflow to follow the release run.
7. Use issue_close to close the shipped issue.
Scope and non-goals
Purpose.
The ship workflow used to have the agent sleep and re-invoke gh in a prose loop, which burned turns and behaved differently every run.
These tools replace that loop with bounded polling, streamed progress, and structured success, timeout, and failure states.
In scope.
Making a tool wait where a human would otherwise wait, making a failure legible as a named reason a prompt can branch on, surviving transient GitHub errors on reads, and refusing to leave an outcome ambiguous.
Non-goals.
- A general-purpose GitHub toolkit.
The surface is scoped to the CI and issue-close flow an agent runs end to end.
An operation with no polling problem — opening a PR, editing labels, dispatching a workflow — is a plain
ghcall and stays one. - Release-tool wrappers.
Earlier versions shipped
release_pr_find,release_pr_merge, andrelease_watch, which encoded release-please's pull-request conventions. A release triggered as a workflow is an ordinary Actions run, soci_findandci_watchalready follow it and no release-specific tool is needed. - A GitHub API client.
The tools shell out to the
ghCLI (andgit, forissue_close's SHA check), and there are no runtime dependencies at all. - Auto-retrying mutations.
Reads retry on transient failures;
issue_closedoes not, since a retried close would post a duplicate comment.
Where adjacent requests belong. Whether to release now, and which packages a release bumps → the calling prompt, not the tool.
Architecture
Portable business logic in src/lib/ — no Pi SDK imports.
Thin Pi wrappers in src/tools/ register each tool and map progress callbacks.
src/
├── extension.ts # Pi extension entry point
├── progress.ts # onProgress → Pi onUpdate adapter
├── tool-result.ts # AgentToolResult helper
├── tools/ # one file per tool (thin wrappers)
└── lib/ # portable business logic
├── ci.ts # findRun, watchRun, listRuns
├── ci-helpers.ts # CIJob, findRetryDelay, formatProgress
├── issue.ts # closeIssue
├── github.ts # gh(), ghJson(), git(), detectRepo()
└── process.ts # runCommand(), sleep()
License
MIT