skip to content
$registry / workers

github

v0.4.2-rc.1

GitHub CLI and event-driven PR monitoring — typed queries and mutations, authenticated temporary webhooks, CI/comment/review notifications, and merge-triggered cleanup.

worker
iiiverified
155 installs12 in 7d3 today
install
$iii trigger compose::add worker=github
  • macOS: arm64 · x64
  • Linux: arm64 · armv7 · x64
  • Windows: arm64 · x64

exact versions are immutable; binary and bundle artifacts are digest-pinned.

skill doc

SKILL.md

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. 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.