Skip to main content

github

Operate GitHub through the gh CLI — typed github::* functions for pull requests, issues, repos, Actions runs/workflows, releases, and search, plus github::exec / github::api escape hatches for everything else.

Source facts

Repository
iii-hq/workers
Last source activity
September 29, 2026 at 10:44
Detected SKILL.md language
English
Stars
114
Forks
26

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
github
description
Operate GitHub through the gh CLI — typed github::* functions for pull requests, issues, repos, Actions runs/workflows, releases, and search, plus github::exec / github::api escape hatches for everything else.
# PR webhook monitoring (opt-in) For durable PR monitoring, use `github::pr::event`, NOT `github::called`. First arm the trigger with a caller-chosen `watch_id`, then call `github::pr::watch` with that same ID, `pr_url` OR `repo` + `number`, optional `events: [ci,comments,reviews,pr]`, `stop_on: merged|closed` (default merged), and mandatory future RFC3339 `expires_at`. Read `github::pr::watch-status` once after watch to close the initial race. Never interval-poll PRs. Inspect `status` and `health.last_error`: `preparing` is not active ingress; `cleanup_pending` is not successful cleanup. `unwatch` and manual `recover` are mutations requiring approval. Internal `github::webhooks::*` functions must not be called by an agent. Event callbacks must dedupe `event_id`; namespace and metadata are preserved, errors propagate to the durable queue. A single passing check is NOT aggregate CI success. Closed without merge remains watched until expiry when stop_on is merged. Operator setup requires persistent SQLite, queue builtin file_based (current Redis adapter is NOT durable), HTTP dedicated public listener, Quick Tunnel, cron, and gh auth with Webhooks write plus repository reads. Default enabled is false. See [the webhook guide](../../docs/architecture/github-webhooks.md). Quick Tunnels are not zero-loss; recovery lists failed deliveries and requests bounded redelivery, reconciling current state. Do not enable merely because a public repository can be read. ## Guided webhook setup `quick-tunnel` is NOT a dependency of this worker: it is only needed for PR webhooks. Call `github::setup::webhooks-status` (read-only) for the checklist, in order: 1. `quick_tunnel` — the quick-tunnel worker is installed (fix: `install_worker`, `compose::add { worker: "quick-tunnel" }`; ask the user first). 2. `cloudflared` — quick-tunnel found the cloudflared binary (fix: `open_url`, Cloudflare's install page). Nothing downloads cloudflared; the user installs it. 3. `http_listener` — the http worker's restricted webhook listener is on (fix: `enable_http_listener`, `github::setup::enable-http-listener`, default port 3112). Each check is `ok`, `missing`, `blocked` (waits for an earlier one) or `unknown` (older worker version or transient error; never blocking). `github::setup::enable-webhooks { enabled: true }` is refused until every check is `ok` and reports `restart_required`: webhook storage opens at startup, so the github worker must restart. `github::pr::watch` refuses definite blockers with the same fix list. The console's GitHub page → Webhooks runs these steps with buttons; both enable functions keep needs_approval for agents. # github The github worker wraps the GitHub CLI (`gh`). Thirty typed functions cover the high-traffic surface (pr, issue, repo, run, workflow, release, search); `github::exec` runs any other gh command verbatim, and `github::api` reaches any GitHub REST endpoint. Auth comes from the worker's GH_TOKEN configuration or the host's ambient `gh auth login` state. There is no local checkout: every repo-scoped call takes an explicit `repo: "owner/name"`. ## When to Use - Check a PR before landing: `github::pr::view`, `github::pr::checks` (failing/pending checks are data, not errors), `github::pr::diff`. - Open or shepherd a PR: `github::pr::create` / `review` / `merge`. - File and triage issues: `github::issue::create` / `list` / `comment` / `close`. - Watch or poke CI: `github::run::list` / `view` / `rerun` / `cancel`; dispatch with `github::workflow::run`. - Cut or inspect releases: `github::release::create` / `list` / `view`. - Find things org-wide: `github::search::repos` / `issues` / `prs` / `code` (qualifiers like `repo:o/r is:open` go in the query string). - Anything gh does that has no typed function → `github::exec { args: [...] }`. - Any REST endpoint → `github::api { path: "repos/o/r/…", jq? }`. ## Boundaries - Needs the gh CLI on the worker host; a missing binary errors at call time with code `gh_not_found` (functions still register without it). - Mutations (create/edit/merge/comment/review/close/rerun/cancel/workflow run/release create) and both escape hatches are approval-gated by default; the read-only surface is allowed (see iii-permissions.yaml). - Curated functions error on a non-zero gh exit (the message carries gh's stderr); `github::exec` returns exit_code/stderr/timed_out as data instead. - Output is capped per stream (default 1 MiB) with `*_truncated` flags; per-call `timeout_ms` clamps to `max_timeout_ms` (default 120 s; 30 s when omitted). - `github::api` paths take concrete owner/repo values — `{owner}`/`{repo}` placeholders need a checkout the worker does not have. ## Functions - `github::pr::*` — list, view, create, edit, merge, comment, review, diff, checks. - `github::issue::*` — list, view, create, edit, comment, close. - `github::repo::*` — view, list. - `github::run::*` — list, view, rerun, cancel (Actions runs). - `github::workflow::*` — list, run (workflow_dispatch). - `github::release::*` — list, view, create. - `github::search::*` — repos, issues, prs, code. - `github::exec` — `{ args, stdin?, timeout_ms? }` → the full outcome as data (`stdout`, `stderr`, `exit_code`, `timed_out`, truncation flags). - `github::api` — `{ path, method?, fields?, body?, jq?, paginate?, timeout_ms? }` → parsed JSON. ## Actionable PR notifications (`agent_actionable`) The default `webhooks.notifications.profile` in `config.yaml` delivers only what needs an agent action, as one `kind: "digest"` payload per watch: - `ci.failed` items: `failure`, `timed_out`, `startup_failure`, `action_required` on the current head. A failed workflow is dropped when its failed job is already reported. Failures of a superseded head are dropped at delivery. - New comments and reviews (created/submitted, approved, changes requested, unresolved threads), excluding edits, deletions, the agent's own login (`ignore_self`, discovered via `GET /user`) and known bot noise. - `merged` / closed lifecycle, delivered immediately with anything pending. Never delivered: CI success or progress, cancelled/skipped/neutral runs, pushes, labels, assignments. The agent checks current CI with `github::pr::checks` when it acts. Every item carries `event_id`; fetch the full event with `github::pr::event-detail`. Timing: a digest is sent after `quiet_ms` (15s) without new items, and never later than `max_wait_ms` (2min) after its first item. `max_items` (30) bounds the payload; extra items are counted in `omitted_items`. ## Watch lifetime follows its listeners A watch is kept alive by the `github::pr::event` bindings that listen to it (same `watch_id`, or a repo/number filter that matches it). - When the last listening binding goes away (its chat was deleted, or it unregistered), the watch is marked orphaned. If no binding listens again within `webhooks.orphan_grace_minutes` (default 60), maintenance stops it, releases its quick-tunnel lease and deletes the repository hook once no live watch remains there; the tunnel stops with its last lease. One-shot wakes are unregistered right after they fire, so re-arm before the grace period ends. - Bindings removed while the worker was offline are reconciled against the engine at most every five minutes. - Calling `github::pr::watch` again with the same `watch_id` and spec resumes a stopped watch; completed (merged/closed) and expired watches stay terminal. - `expires_at` must be within `webhooks.max_watch_days` (1..=30, default 30): a watch holds a quick-tunnel lease, and leases last at most 30 days.
View on GitHub