Replace gh with octokit in os-backlog #857

Closed
opened 2026-09-30 18:14:37 +00:00 by jared · 7 comments
Owner

Problem

os-backlog runs the gh CLI for every GitHub operation. Ticket text goes through argv, and gh issue create output is parsed with a regex. ADR-0256 replaces gh with the octokit gem.

plugins/os-backlog/lib/backlog/gh_backend.rb:9-11   gh issue create --repo S --title T --body B [--label x]   (regex on stdout)
plugins/os-backlog/lib/backlog/gh_backend.rb:85     gh issue view N --repo S --json <fields>
plugins/os-backlog/lib/backlog/gh_backend.rb:198    gh issue edit N --repo S --add-label/--remove-label/--add-assignee/--remove-assignee/--body-file
plugins/os-backlog/lib/backlog/issue_show.rb:36     gh issue view N --repo S --json title,body,state,labels
plugins/os-backlog/lib/backlog/inspect_command.rb:104   gh issue list --repo S --state open --json ...
plugins/os-backlog/bin/wakeup-poll:16               gh issue list --repo S --state open --json ...

Reproduce

n/a: design change from ADR-0256.

Approach

A new Backlog::GithubBackend keeps GhBackend's public interface and delegates each call to an Octokit::Client built with access_token: ENV.fetch("GITHUB_TOKEN"). The octokit methods are create_issue, issue, list_issues, labels, add_comment, issue_comments, close_issue, add_labels_to_an_issue, remove_label, and update_issue. IssueShow, InspectCommand#gh_issues, and bin/wakeup-poll read through the same backend. GhBackend and its argv builders are deleted.

Required work:

  1. Load octokit in os-backlog with the same dependency method as the git gem (session f531ed01).

Rejected: keep gh and read gh auth token — that is a shell call again (ADR-0256).

Acceptance criteria

  1. Given a github: tracker, when issue-create runs with a body that starts with --label, then the created issue stores that body unchanged and the command prints the new number and URL.
  2. Given a github: tracker, when issue-show, comment, close, issue-edit, and label add/remove run, then each one sends the matching GitHub API request and no gh process starts.
  3. Given GITHUB_TOKEN is not set, when any GitHub command runs, then it exits non-zero with a message that names GITHUB_TOKEN.
  4. Given wakeup-poll runs for a github: project, when open issues exist, then it lists them as it does today.
  5. Given a failed GitHub comment read, when issue-comments runs, then the failure reaches the caller (inventory defect 5).
  6. Given a GitHub ticket with an assignee, when another assignee is set, then the new assignee replaces the old one, as on Forgejo (inventory defect 13).

Owner sketch

class Backlog::GithubBackend
  def initialize(client: Octokit::Client.new(access_token: ENV.fetch("GITHUB_TOKEN")))
  def create(slug, title:, body:, labels: [])   # => { number:, url: }
  # ... the rest of GhBackend's public methods
end

Current paths

The gh calls now sit in plugins/os-backlog/lib/backlog/issues/gh_backend.rb, issues/gh_issue.rb, issue_show/github_view.rb, and inspector/gh_issues.rb. activemodel set the dependency method: the Gemfile. This ticket runs before port slice #1616, which wraps the new backend in Host::GitHub.

Non-goals

  • Forgejo. It has its own ticket.
  • os-sdlc's gh call. It is in the os-sdlc adoption ticket.

Blocked by

  • The git gem dependency method (session f531ed01). os-backlog has no Gemfile today.
  • GITHUB_TOKEN must be set in ~/.credentials before a live check. The acceptance tests stub the API.

Origin

  • Trigger: #845 audit; ADR-0256 decided 2026-09-30.
  • Improvised this session: none
  • Chain: ticket text in argv and a regex on create output ← GhBackend shells out to gh ← DESIGN: ADR-0123, amended by ADR-0256.
  • Root candidate: this ticket
  • Where: plugins/os-backlog/lib/backlog/gh_backend.rb, issue_show.rb, inspect_command.rb, bin/wakeup-poll
  • Session: f090dd39-8ad6-4f4e-8743-7bbedb8f08d4
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/f090dd39-8ad6-4f4e-8743-7bbedb8f08d4.jsonl
## Problem os-backlog runs the `gh` CLI for every GitHub operation. Ticket text goes through argv, and `gh issue create` output is parsed with a regex. ADR-0256 replaces gh with the octokit gem. ``` plugins/os-backlog/lib/backlog/gh_backend.rb:9-11 gh issue create --repo S --title T --body B [--label x] (regex on stdout) plugins/os-backlog/lib/backlog/gh_backend.rb:85 gh issue view N --repo S --json <fields> plugins/os-backlog/lib/backlog/gh_backend.rb:198 gh issue edit N --repo S --add-label/--remove-label/--add-assignee/--remove-assignee/--body-file plugins/os-backlog/lib/backlog/issue_show.rb:36 gh issue view N --repo S --json title,body,state,labels plugins/os-backlog/lib/backlog/inspect_command.rb:104 gh issue list --repo S --state open --json ... plugins/os-backlog/bin/wakeup-poll:16 gh issue list --repo S --state open --json ... ``` ## Reproduce n/a: design change from ADR-0256. ## Approach A new `Backlog::GithubBackend` keeps `GhBackend`'s public interface and delegates each call to an `Octokit::Client` built with `access_token: ENV.fetch("GITHUB_TOKEN")`. The octokit methods are `create_issue`, `issue`, `list_issues`, `labels`, `add_comment`, `issue_comments`, `close_issue`, `add_labels_to_an_issue`, `remove_label`, and `update_issue`. `IssueShow`, `InspectCommand#gh_issues`, and `bin/wakeup-poll` read through the same backend. `GhBackend` and its argv builders are deleted. Required work: 1. Load `octokit` in os-backlog with the same dependency method as the git gem (session f531ed01). Rejected: keep gh and read `gh auth token` — that is a shell call again (ADR-0256). ## Acceptance criteria 1. Given a `github:` tracker, when `issue-create` runs with a body that starts with `--label`, then the created issue stores that body unchanged and the command prints the new number and URL. 2. Given a `github:` tracker, when `issue-show`, `comment`, `close`, `issue-edit`, and label add/remove run, then each one sends the matching GitHub API request and no `gh` process starts. 3. Given `GITHUB_TOKEN` is not set, when any GitHub command runs, then it exits non-zero with a message that names `GITHUB_TOKEN`. 4. Given `wakeup-poll` runs for a `github:` project, when open issues exist, then it lists them as it does today. 5. Given a failed GitHub comment read, when `issue-comments` runs, then the failure reaches the caller (inventory defect 5). 6. Given a GitHub ticket with an assignee, when another assignee is set, then the new assignee replaces the old one, as on Forgejo (inventory defect 13). ## Owner sketch ```ruby class Backlog::GithubBackend def initialize(client: Octokit::Client.new(access_token: ENV.fetch("GITHUB_TOKEN"))) def create(slug, title:, body:, labels: []) # => { number:, url: } # ... the rest of GhBackend's public methods end ``` ## Current paths The `gh` calls now sit in `plugins/os-backlog/lib/backlog/issues/gh_backend.rb`, `issues/gh_issue.rb`, `issue_show/github_view.rb`, and `inspector/gh_issues.rb`. `activemodel` set the dependency method: the Gemfile. This ticket runs before port slice #1616, which wraps the new backend in `Host::GitHub`. ## Non-goals - Forgejo. It has its own ticket. - os-sdlc's `gh` call. It is in the os-sdlc adoption ticket. ## Blocked by - The git gem dependency method (session f531ed01). os-backlog has no Gemfile today. - `GITHUB_TOKEN` must be set in `~/.credentials` before a live check. The acceptance tests stub the API. ## Origin - Trigger: #845 audit; ADR-0256 decided 2026-09-30. - Improvised this session: none - Chain: ticket text in argv and a regex on create output ← GhBackend shells out to gh ← DESIGN: ADR-0123, amended by ADR-0256. - Root candidate: this ticket - Where: plugins/os-backlog/lib/backlog/gh_backend.rb, issue_show.rb, inspect_command.rb, bin/wakeup-poll - Session: f090dd39-8ad6-4f4e-8743-7bbedb8f08d4 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/f090dd39-8ad6-4f4e-8743-7bbedb8f08d4.jsonl
Author
Owner

Blocked by #866 (Forgejo dependency recorded).

Blocked by #866 (Forgejo dependency recorded).
Author
Owner

Jared confirmed on 2026-11-06 (session 1a5b2630) that the move from the gh CLI to the octokit gem is certain. Current files differ from the paths in the body: the gh calls are in plugins/os-backlog/lib/backlog/issues/gh_backend.rb (gh issue create, list, comment, close, label list), issues/gh_issue.rb, and issue_show/github_view.rb. os-sdlc already uses octokit in plugins/os-sdlc/lib/os_sdlc/tracker/issue_source/github.rb; reuse its shape. This work is separate from the os-git git-command work (see the os-git orchestrator ticket); it covers GitHub API calls only. Re-read the body before implementation, because the file paths in it are stale.

Jared confirmed on 2026-11-06 (session 1a5b2630) that the move from the gh CLI to the octokit gem is certain. Current files differ from the paths in the body: the gh calls are in plugins/os-backlog/lib/backlog/issues/gh_backend.rb (gh issue create, list, comment, close, label list), issues/gh_issue.rb, and issue_show/github_view.rb. os-sdlc already uses octokit in plugins/os-sdlc/lib/os_sdlc/tracker/issue_source/github.rb; reuse its shape. This work is separate from the os-git git-command work (see the os-git orchestrator ticket); it covers GitHub API calls only. Re-read the body before implementation, because the file paths in it are stale.
Author
Owner

Port slice #1616 does this work through the GitHub host. Close this ticket when #1616 ships.

Port slice #1616 does this work through the GitHub host. Close this ticket when #1616 ships.
Author
Owner

Correction to my earlier comment: this ticket runs first and stays open on its own. Port slice #1616 now waits for it and wraps GithubBackend in Host::GitHub. This ticket also takes inventory defects 5 and 13.

Correction to my earlier comment: this ticket runs first and stays open on its own. Port slice #1616 now waits for it and wraps GithubBackend in Host::GitHub. This ticket also takes inventory defects 5 and 13.
Author
Owner

Work started on branch ticket-857.

Work started on branch ticket-857.
Author
Owner

Resolution

Done: GithubBackend replaces every gh call through octokit in Issues, IssueShow, Inspector, and wakeup-poll. Missing GITHUB_TOKEN names the variable. Defects 5 and 13 fixed. Old gh classes deleted.

Evidence: Merged to main in 444bb648. os-backlog suite on seed 19992 and 3 random seeds: 425 runs, 0 failures. A real read of rails/thor returned 117 issues and 9 labels. Design audit findings fixed or answered.

Follow-ups: Route skill gh text: #1621 (commented). os-sdlc activemodel removal: #1623 (commented). Forgejo network call in a test: #1620 (commented).

## Resolution **Done:** GithubBackend replaces every gh call through octokit in Issues, IssueShow, Inspector, and wakeup-poll. Missing GITHUB_TOKEN names the variable. Defects 5 and 13 fixed. Old gh classes deleted. **Evidence:** Merged to main in 444bb648. os-backlog suite on seed 19992 and 3 random seeds: 425 runs, 0 failures. A real read of rails/thor returned 117 issues and 9 labels. Design audit findings fixed or answered. **Follow-ups:** Route skill gh text: #1621 (commented). os-sdlc activemodel removal: #1623 (commented). Forgejo network call in a test: #1620 (commented).
Author
Owner

Removed the native Forgejo dependency on #866. This ticket shares no work with #866. To restore it, add the dependency again.

Removed the native Forgejo dependency on #866. This ticket shares no work with #866. To restore it, add the dependency again.
jared closed this issue 2026-11-06 21:38:00 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#857
No description provided.