Skip to content

GitHub Link Tracking & Live Status

Status: Open — design proposal (Phase 2, Agent Orchestrator Research Program)

Once the agent has emitted <jackin:issue> or <jackin:pr> tags via the agent tag protocol, the operator wants to see their live state: is the issue still open? Did the PR get approved? Did CI go green? Today jackin’ has no GitHub status awareness at all — the operator switches to a browser tab to check.

Polling GitHub for every link on every console redraw would burn the rate limit instantly, so this needs a small cache and an awareness of which states change rarely vs frequently.

  • It’s the most operator-visible payoff of the tag protocol — without live status, the protocol just stores URLs.
  • It lets the autonomous queue (Phase 4) act on PR state (“re-queue a task whose PR was rejected”) without re-implementing GitHub polling inside the queue.
  • It’s the lowest-risk way to introduce a third-party network dependency (Octocrab) into jackin’s runtime — the surface is narrow (read-only status fetches) and the failure mode is obvious (status cell shows ”?”).

Sources:

multicode polls GitHub via Octocrab on a per-link cadence that varies by state. Cached in per-workspace SQLite (.multicode/cache.sqlite), table github_link_statuses. Refresh windows:

StateRefresh after
Open issue10 min
Closed issue60 min
PR building1 min
PR built, review pending5 min
PR approved, awaiting merge10 min
PR closed/merged60 min
On fetch error5 min retry

Cached fields per row include: URL, kind (issue/PR), host, owner, repo, resource number, issue state, PR state, build state, review state, draft flag, fetched-at, refresh-after, last error.

The TUI renders icons:

  • Issue: blue circle (open), gray X (closed)
  • PR: state colors plus draft badge, build status (running/success/fail), review status (none/pending/changes/approved)

Reuse multicode’s polling cadence model verbatim — they did the work to calibrate it against real GitHub usage. Use Octocrab as the client. Persist via the persistent storage layer.

Reuses the credential source pattern: the operator’s GitHub PAT comes from one of env, command, op://, or keychain. Required scopes: public_repo for public repos, repo for private. read:user for resolving avatars later.

The existing gh CLI passthrough is separate and remains how the container talks to GitHub. The link-tracking client is operator-host only — the agent doesn’t see the token.

CREATE TABLE github_link_statuses (
url TEXT PRIMARY KEY,
kind TEXT NOT NULL, -- 'issue' or 'pr'
host TEXT NOT NULL,
owner TEXT NOT NULL,
repo TEXT NOT NULL,
resource_number INTEGER NOT NULL,
issue_state TEXT, -- 'open' | 'closed' | NULL
pr_state TEXT, -- 'open' | 'merged' | 'closed' | NULL
build_state TEXT, -- 'pending' | 'success' | 'failure' | 'error' | NULL
review_state TEXT, -- 'none' | 'pending' | 'changes_requested' | 'approved'
pr_is_draft BOOLEAN,
fetched_at INTEGER NOT NULL, -- epoch seconds
refresh_after INTEGER NOT NULL, -- epoch seconds
last_error TEXT
);

Cache is per-instance (each ~/.jackin/data/<container>/ has its own SQLite). Sharing a cache across instances would be a small efficiency win but creates state-isolation questions — defer.

A single async task per running console session (not per-instance) walks all known links across instances, picks ones whose refresh_after is in the past, fetches in batches of N (default 5) to avoid burst rate limit consumption, updates the cache.

Failures: log to last_error, set refresh_after = now + 5 min, console renders a yellow ”?” until success.

Each instance row gets a “Links” cell (or expand-to-detail panel) that shows captured <jackin:issue> and <jackin:pr> markers as colored icons, with hover/select revealing details. Clicking opens via the web handler.

  • Octocrab-based fetcher with multicode’s cadence table.
  • Per-instance SQLite cache (depends on persistent storage layer).
  • Console icons for issue/PR state, build, review.
  • Operator-host PAT via the existing credential resolution (op://, ${env.VAR}, literal). New backends added when credential source pattern lands.
  • Console “Links” panel/cell rendering.
  • Click-to-open via the web handler from operator handler system.
  • Custom-link CRUD from the console (multicode allows manually adding links not emitted by the agent). Useful but waits — the agent-emitted flow covers the 95% case.
  • GitHub Enterprise host support beyond the standard https://github.com/<owner>/<repo> URL pattern. multicode supports it; jackin’ V1 should too if cost is low (Octocrab handles GHE clients with one extra config line). Confirm in design.
  • PR review summary text (who approved, what comments). Just state in V1.
  • Cross-link aggregation (“show me all open PRs across all instances”). Defer until Phase 4.
  • GitLab / Bitbucket. Defer indefinitely; if demand surfaces, abstract the fetcher behind a LinkProvider trait.
  • Per-instance cache vs operator-global. Per-instance matches jackin’s existing data layout but means a link tracked by two instances gets fetched twice. Recommended default: per-instance for V1; revisit if rate-limit pressure shows up.
  • Token scope guidance. What’s the minimum-privilege token the docs should recommend? public_repo works for public-only; private repos need repo. multicode docs are clear on this; jackin’s docs should match.
  • GitHub App alternative. Long-term, a GitHub App (with per-installation tokens) is more durable than a PAT. Defer the design but flag it for the multi-tenant Kubernetes future.
  • New module (e.g. src/runtime/link_tracking.rs) — fetcher loop + cadence + cache writes
  • src/console/manager/state.rs — links panel
  • src/console/manager/render/ — icon rendering
  • The persistent-storage module owns the SQL schema