ProductOperator experience

GitHub Link Tracking & Live Status: Design Exploration

Designs GitHub link recognition, status refresh, caching, and operator presentation for work attached to agent sessions.

Research state: Incomplete

Summary

GitHub links should attach to agent sessions as typed work references with cached status and explicit refresh behavior.

This exploration informs GitHub link tracking and live status in the Agent Orchestration Program.

Research question

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.

Why it matters

  • It's the most operator-visible payoff of the tag protocol — without live status, the protocol just stores URLs.
  • It lets the roadmap-owned Autonomous task queue 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 runtime — the surface is narrow (read-only status fetches) and the failure mode is obvious (status cell shows "?").

Inspiration in multicode

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.

Auth source

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.

Schema (in the SQLite layer)

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.

Fetcher loop

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.

Console rendering

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.

Scope

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

Out of scope

  • 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.
  • PR review summary text beyond status.
  • Cross-link aggregation across all instances.
  • GitLab and Bitbucket providers; a future provider need should introduce a LinkProvider boundary.

Limitations and open questions

  • Per-instance cache vs operator-global. Per-instance matches jackin existing data layout but means a link tracked by two instances gets fetched twice. Recommended default: per-instance; 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 docs should match.
  • GitHub App alternative. A GitHub App with per-installation tokens is more durable than a PAT but remains outside the current single-operator design.

Code touchpoints

  • New module (e.g. src/runtime/link_tracking.rs) — fetcher loop + cadence + cache writes
  • crates/jackin-capsule/src/pr_context.rs — existing focused-instance PR context this feature extends
  • src/console/tui/view/ — icon rendering
  • The persistent-storage module owns the SQL schema

On this page