Replace gh PR wrapper with Octokit
Context and Problem Statement
Section titled “Context and Problem Statement”auto-pr-create-or-update-pr currently depends on a live PullRequestClient that shells out to gh pr view/edit/create.
This creates avoidable runtime coupling to:
- GitHub CLI presence and version on runners.
- CLI output shapes (including URL parsing from
gh pr createstdout). - Subprocess error text classification.
- Implicit repository resolution behavior inside
gh.
The workflow already depends on a tagless-final boundary (PullRequestClientService), so the live interpreter can change without changing workflow orchestration.
Considered Options
Section titled “Considered Options”- Keep
ghwrapper — No migration cost, but keeps subprocess and CLI coupling in the critical PR path. - Use raw
fetchagainst GitHub REST API — Removes CLI dependency but requires manual request typing, pagination/shape handling, and error wrapping. - Use Octokit (
octokit) — Official GitHub JavaScript SDK with typed REST calls and stable client ergonomics.
Decision Outcome
Section titled “Decision Outcome”Chosen option: replace the gh-backed live PR client with Octokit while keeping the existing PullRequestClientService interface unchanged.
Design details
Section titled “Design details”- Keep
findByBranch,create, andupdatesignatures unchanged at the service boundary. - Replace only
src/auto-pr/live/pull-request-client.tsimplementation. - Resolve repository identity explicitly:
- Prefer
GITHUB_REPOSITORY. - Fall back to
GH_REPO. - Require strict
owner/repoformat.
- Prefer
- Construct
OctokitwithGH_TOKEN. - Read PR body markdown via Effect
FileSystemand send the content in REST payloads. - Use REST operations:
- lookup:
octokit.rest.pulls.list({ owner, repo, state: "open", head: "${owner}:${branch}", per_page: 1 }) - update:
octokit.rest.pulls.update({ owner, repo, pull_number, title, body }) - create:
octokit.rest.pulls.create({ owner, repo, head, base, title, body })
- lookup:
- Map failures to existing domain errors:
- lookup failures ->
PullRequestLookupError - create/update/config failures ->
PullRequestFailedError
- lookup failures ->
Consequences
Section titled “Consequences”- Removes runtime dependence on
ghfor PR lifecycle operations. - Removes stdout parsing for created PR URL.
- Uses GitHub-maintained, typed SDK for REST interactions.
- Preserves workflow shell behavior through unchanged tagless-final boundary.
- Adds runtime dependency on
octokit. - Requires explicit repository identity (
owner/repo) in environment. - Test strategy moves from process-spawner mocks to Octokit API behavior doubles.
Neutral
Section titled “Neutral”GH_TOKENremains the auth input.- Local
gh actsupport inscripts/act-local-ci.tsis unchanged. - Workflow permissions model stays the same for create/update (
contents: read,pull-requests: write).
References
Section titled “References”- Spec:
docs/superpowers/specs/2026-05-01-octokit-pr-client-design.md - GitHub REST scripting guide: https://docs.github.com/en/rest/guides/scripting-with-the-rest-api-and-javascript
- Octokit: https://github.com/octokit/octokit.js/