You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Detect the git forge behind a project's remote and show the pull/merge request linked to each thread, for GitHub, GitLab, Gitea, Forgejo, Bitbucket and Azure DevOps, including self-hosted instances, using each forge's CLI where one exists.
Tcode today
Nothing forge-related exists: no remote get-url, no forge detection, no PR model (crates/services/src/git.rs only checks that a remote named origin exists). ureq is already a services dependency for REST fallbacks. The module doc of crates/core/src/git.rs says it "excludes PR/MR operations"; that is a derived comment and should be corrected with this work.
Associations (no model-facing tool)
T3 Code has two concepts; Tcode adopts both, minus T3's agent-facing MCP link tool (explicit non-goal):
Branch PR: looked up automatically for the thread's branch (worktree path if any, else project root). One per thread, display-only, re-checked after each turn so a PR the agent opened with its own tools is found without any injection.
Linked PRs: explicit links with a stored snapshot, several per thread (key {host, repo, number}). Sources: created (Tcode's own create-PR action, Source control: Open PR action usable during a run, with merge when CI passes #533) and manual (paste a URL, or "Link to thread" on a PR link in the transcript). Links win over the branch PR for display; unlinking falls back to the branch PR.
Choosing a PR for a branch: skip unpublished branches; never match via an upstream that is the default branch; prefer open/draft, then most recently updated; require the head owner to match so fork PRs do not collide (GitLab and Forgejo reuse branch names, seen live).
Explicit user mapping (git host → forge kind + optional web/API host; the git host and web host can differ).
Known public hosts: github.com, *.ghe.com, gitlab.com, codeberg.org (Forgejo), gitea.com, bitbucket.org, dev.azure.com, *.visualstudio.com.
Hosts configured in the CLIs as the source of truth for self-hosted instances: gh auth status --json hosts, the hosts section of glab's config.yml, tea logins list -o json, fj's keys.json. (T3 Code has no refinement for GitHub Enterprise on domains without a github label; Tcode should.)
Unauthenticated probes, cached per host with a short timeout: /api/forgejo/v1/version 200 → Forgejo; /api/v1/version → Gitea; /api/v4/version 401 with x-gitlab-meta → GitLab; /api/v3/meta → GitHub Enterprise Server.
Normalize SSH hosts first (strip port, apply SSH config aliases and fj aliases).
Per-forge backends (crates/services/src/forge.rs, via the process helpers)
Forge
PR for branch
Pitfalls
GitHub / GHES
gh pr list -H X -s all --json …; checks via gh pr checks --json bucket
REST head= without owner: is silently ignored; reviewDecision is "" when not required
GitLab (incl. self-managed)
glab mr list --source-branch X -A -F json
mr view <branch> prompts on multiple matches; head_pipeline only on single-MR GET; glab auth status has no JSON
Gitea
tea api '/repos/{owner}/{repo}/pulls/BASE/OWNER:X'
tea pulls list cannot filter by branch; list JSON values are strings, no draft
Forgejo / Codeberg
REST /pulls?head=X&state=all (v16+), token from fj's keys.json or tea
fj has no JSON output; AGit PRs keep the branch in head.label
Bitbucket Cloud / DC
REST only (no official CLI); API tokens (app passwords ended 2026-06)
Repeat state=; defaults to OPEN
Azure DevOps
az repos pr list --source-branch X --status all -o json
Checks come from policy evaluations
Gerrit and SourceHut are out of scope (Gerrit cannot see local branch names; SourceHut has no PRs). Universal token fallback: git credential fill with GIT_TERMINAL_PROMPT=0.
Refresh
Host-side, with no client required: branch PR after each turn end and on branch/worktree changes; linked PRs sweep every minute (open PRs every minute, closed every 15 min, merged never unless requested); group by PR key so a PR shared by threads is read once; per-(forge, host, credential) rate-limit pauses honouring Retry-After, exponential backoff 30 s → 15 min. Missing or logged-out CLIs appear in Settings with the install/login hint; background lookups back off instead of looping.
UI
Sidebar badge (state glyph + number; +N for several links), thread header badge with checks and review glyphs, open in browser, link/unlink actions. Strings in both locales.
Summary
Detect the git forge behind a project's remote and show the pull/merge request linked to each thread, for GitHub, GitLab, Gitea, Forgejo, Bitbucket and Azure DevOps, including self-hosted instances, using each forge's CLI where one exists.
Tcode today
Nothing forge-related exists: no
remote get-url, no forge detection, no PR model (crates/services/src/git.rsonly checks that a remote namedoriginexists).ureqis already aservicesdependency for REST fallbacks. The module doc ofcrates/core/src/git.rssays it "excludes PR/MR operations"; that is a derived comment and should be corrected with this work.Associations (no model-facing tool)
T3 Code has two concepts; Tcode adopts both, minus T3's agent-facing MCP link tool (explicit non-goal):
{host, repo, number}). Sources:created(Tcode's own create-PR action, Source control: Open PR action usable during a run, with merge when CI passes #533) andmanual(paste a URL, or "Link to thread" on a PR link in the transcript). Links win over the branch PR for display; unlinking falls back to the branch PR.Normalized model (
crates/core)Forge detection order
*.ghe.com, gitlab.com, codeberg.org (Forgejo), gitea.com, bitbucket.org, dev.azure.com,*.visualstudio.com.gh auth status --json hosts, thehostssection of glab'sconfig.yml,tea logins list -o json,fj'skeys.json. (T3 Code has no refinement for GitHub Enterprise on domains without agithublabel; Tcode should.)/api/forgejo/v1/version200 → Forgejo;/api/v1/version→ Gitea;/api/v4/version401 withx-gitlab-meta→ GitLab;/api/v3/meta→ GitHub Enterprise Server.Normalize SSH hosts first (strip port, apply SSH config aliases and
fjaliases).Per-forge backends (
crates/services/src/forge.rs, via the process helpers)gh pr list -H X -s all --json …; checks viagh pr checks --json buckethead=withoutowner:is silently ignored;reviewDecisionis""when not requiredglab mr list --source-branch X -A -F jsonmr view <branch>prompts on multiple matches;head_pipelineonly on single-MR GET;glab auth statushas no JSONtea api '/repos/{owner}/{repo}/pulls/BASE/OWNER:X'tea pulls listcannot filter by branch; list JSON values are strings, no draft/pulls?head=X&state=all(v16+), token fromfj'skeys.jsonorteafjhas no JSON output; AGit PRs keep the branch inhead.labelstate=; defaults to OPENaz repos pr list --source-branch X --status all -o jsonGerrit and SourceHut are out of scope (Gerrit cannot see local branch names; SourceHut has no PRs). Universal token fallback:
git credential fillwithGIT_TERMINAL_PROMPT=0.Refresh
Host-side, with no client required: branch PR after each turn end and on branch/worktree changes; linked PRs sweep every minute (open PRs every minute, closed every 15 min, merged never unless requested); group by PR key so a PR shared by threads is read once; per-(forge, host, credential) rate-limit pauses honouring
Retry-After, exponential backoff 30 s → 15 min. Missing or logged-out CLIs appear in Settings with the install/login hint; background lookups back off instead of looping.UI
Sidebar badge (state glyph + number;
+Nfor several links), thread header badge with checks and review glyphs, open in browser, link/unlink actions. Strings in both locales.Reference
T3 Code origin/main:
apps/server/src/sourceControl/*,ThreadPullRequestReactor.ts,PullRequestSyncReactor.ts,packages/shared/src/threadPullRequests.ts, migrations 042/048/050; #8160, #10101, #10839, #11436.