Skip to content

feat(server): resolve GitHub issues and prepare an issue worktree thread - #4

Merged
Artic0din merged 46 commits into
mainfrom
feat/2-resolve-github-issues
Oct 6, 2026
Merged

Artic0din merged 46 commits into
mainfrom
feat/2-resolve-github-issues

Conversation

@Artic0din

Copy link
Copy Markdown
Owner

Problem

There is no way to start agent work from a GitHub issue.
The user has to read the issue on GitHub, create a branch and worktree by hand, and paste the issue into the composer.
This PR is the server half of the fork experiment tracked in #1.

Change

  • git.resolveIssue reads one issue through gh issue view, behind a new optional getIssue capability on source control providers. Only GitHub implements it; other hosts get "Only GitHub issues are supported."
  • git.prepareIssueThread resolves the issue, then creates a worktree on issue/<number>-<slug> from the default branch and runs the project setup script.
  • Starting the same issue again reuses its worktree, even if the issue title changed since. An existing branch without a worktree is checked out instead of recreated.
  • A stale worktree registration (folder deleted by hand) is pruned first. An issue branch checked out in the main repo is refused rather than handed back as a worktree.
  • A pull request number or URL is rejected with "#N is a pull request, not an issue." A missing number says "Issue N not found."

The web dialog that calls these RPCs follows in a stacked PR for #3.

Scope and approval

Fork-only experiment, tracked in #1 and #2.
Upstream context: pingdotgg#11067 suggests "creating a thread from an issue can follow" the first Issues slice. This change deliberately has no issue browsing UI.

Verification

  • 388 tests pass across the 9 touched test files (GitManager, GitWorkflowService, GitHubSourceControlProvider, GitHubCli, VcsProcess, GitHubPullRequestCli, shared git, contracts git and rpc).
  • New tests: issue reference parsing, branch naming (emoji-only and "Update" titles), resolve by number, open and merged PR numbers rejected, missing issue, unsupported host, worktree created from main, reuse on second start, reuse after a title change, existing branch without a worktree, deleted worktree folder, branch checked out in the main repo.
  • apps/server and packages/contracts typecheck clean.
  • Real gh against this fork: a fork issue URL resolves; a bare 1 resolves against origin (upstream) and hits upstream PR feat: start agent work from a GitHub issue #1, which is how the merged-PR bug was found and fixed.
  • Not checked: the UI (lands in the next PR).

Release note: Agents can start work from a GitHub issue in its own worktree (server support).

Fixes #2

Implemented by Claude Opus 5.5 (1M context) in Claude Code, running inside T3 Code.

🤖 Generated with Claude Code

Artic0din and others added 6 commits October 5, 2026 20:15
Adds the helpers the start-from-issue flow shares between server and
web: one normalizes an issue number or GitHub issue URL, the other names
the worktree branch issue/<number>-<slug>.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds git.resolveIssue and git.prepareIssueThread with their schemas so
clients can read a GitHub issue and start a worktree thread from it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds an optional getIssue capability to source control providers,
implemented for GitHub with gh issue view, and a GitManager.resolveIssue
service method behind the git.resolveIssue RPC. Pull request numbers and
hosts without the capability fail with a clear message.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
GitManager.prepareIssueThread resolves the issue, then creates a worktree
on issue/<number>-<slug> from the default branch and runs the project
setup script. Starting the same issue again reuses its worktree, and an
existing issue branch without a worktree is checked out instead of
recreated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gh issue view reports a pull request's state as MERGED, which the issue
decoder rejected, so pasting a merged PR number showed a generic read
error instead of the pull request message.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review follow-ups for the issue thread flow:
- A missing issue number now says the issue was not found instead of a
  generic CLI failure.
- An issue branch checked out in the main repo is refused rather than
  handing the main checkout back as a worktree.
- Stale worktree registrations are pruned first, so a worktree folder
  deleted by hand no longer blocks starting the issue again.
- Reuse matches the issue number prefix, so a renamed issue finds its
  existing branch and worktree.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-06T03:04:16.348179Z eb9b318 New commits
🔒 Security Review ✅ Completed 2026-10-05T09:37:38.087498Z 6dec9d3 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Artic0din and others added 2 commits October 5, 2026 20:27
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="apps/server/src/git/GitManager.ts" line_range="2405-2414" />
<code_context>
+      const existing =
+        localRefs.find((ref) => ref.name === branch) ??
+        localRefs.find((ref) => ref.name.startsWith(issueBranchPrefix));
+      if (existing?.worktreePath) {
+        const rootWorktreePath = yield* canonicalizeExistingPath(input.cwd);
+        if ((yield* canonicalizeExistingPath(existing.worktreePath)) === rootWorktreePath) {
+          return yield* new GitManagerError({
+            operation: "prepareIssueThread",
+            cwd: input.cwd,
+            detail: `${existing.name} is already checked out in the main repo. Switch the main repo off that branch to start a worktree thread.`,
+          });
+        }
+        return { issue, branch: existing.name, worktreePath: existing.worktreePath };
+      }
+
</code_context>
<issue_to_address>
**issue (bug_risk):** The main-checkout comparison canonicalizes `input.cwd` rather than the repository root, so a request whose `cwd` is a subdirectory of the main repository is treated as a different worktree and returns the main checkout as the issue worktree even though that branch is checked out in the main repo.

**Triggers:** When `cwd` points to a subdirectory inside the repository and the matching issue branch is checked out in the main checkout.

**Suggested fix:** Resolve `input.cwd` to the Git worktree root before comparing it with `existing.worktreePath`, or obtain the root from Git directly.
</issue_to_address>

Fix all in Cursor


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread apps/server/src/git/GitManager.ts Outdated
Artic0din and others added 3 commits October 5, 2026 20:29
Adds the Start work from issue dialog. It resolves the issue, prepares
its worktree, opens the project draft there, and prefills the composer
with the issue without discarding text already typed in the draft.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds a Start work from issue command palette action and a branch picker
item for issue 123 or a GitHub issue URL. Bare numbers stay pull request
checkout. Documents the flow in the source control guide.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review follow-ups:
- The palette action now works from any thread. It opens the project's
  draft first, because the dialog only mounts on a draft.
- Matching an issue URL in the draft uses whole tokens, so issue 3 is
  no longer skipped when the draft mentions issue 31.
- Starting a second issue replaces the first issue's untouched prompt
  instead of appending to it. Edited text is still kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6dec9d3137

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/server/src/git/GitManager.ts Outdated
Comment thread packages/shared/src/git.ts
Comment thread apps/server/src/git/GitManager.ts Outdated
Comment thread apps/server/src/git/GitManager.ts Outdated
Comment thread apps/server/src/git/GitManager.ts
Comment thread apps/server/src/sourceControl/GitHubSourceControlProvider.ts Outdated
Artic0din and others added 2 commits October 5, 2026 20:48
The provider registry rebuilds each provider with its remote context
and dropped the optional getIssue capability, so every real project
reported that only GitHub issues are supported. Found in a manual run
against a GitHub clone; the earlier tests injected the provider
directly and bypassed the registry.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Artic0din

Copy link
Copy Markdown
Owner Author

Pushed 64abefd: fix(server): keep the issue capability when routing to a provider.

The manual pass for #5 found that SourceControlProviderRegistry.bindProviderContext rebuilt each provider without the optional getIssue capability, so every real project reported "Only GitHub issues are supported". The earlier GitManager tests injected the provider directly and bypassed the registry. New test: 'keeps the issue capability on a resolved GitHub provider' (failed first, passes now; registry suite 13/13).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 64abefd646

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/server/src/git/GitManager.ts
Artic0din and others added 6 commits October 5, 2026 21:06
- Look up issue branches with a prefix query, so repositories with more
  than one page of refs still find an existing issue worktree.
- Detect the main checkout when the project folder is a subdirectory of
  the repository.
- Fail when the default branch is unknown instead of branching from the
  current checkout, which could carry unrelated commits.
- Serialize issue starts so two clients starting the same issue get the
  same worktree instead of a git conflict.
- Continue an issue branch that exists only on the remote instead of
  recreating it from the default branch.
- Raise the gh output cap so the largest issue bodies decode.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- An issue URL followed by punctuation in the draft is recognized, so
  starting the same issue again does not add it twice.
- If opening the draft fails after the worktree is created, the dialog
  shows the error instead of failing silently. Starting again reuses
  the worktree.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Clients use it to hide Start from issue on servers that do not serve
git.resolveIssue and git.prepareIssueThread.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codex review follow-ups:
- A prompt that mixes user text with an issue is never marked as
  replaceable, so a later issue start appends instead of deleting the
  user's text.
- Start from issue appears only when the server advertises issueThreads
  and the project is not the scratch project.
- The dialog request carries its project; a chat view for another
  project drops it instead of starting work in the wrong repository.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5f2507ab99

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/server/src/git/GitManager.ts
Comment thread apps/server/src/git/GitManager.ts Outdated
Comment thread apps/server/src/sourceControl/GitHubSourceControlProvider.ts
Artic0din and others added 2 commits October 5, 2026 21:24
gh issue view bypassed the shared GraphQL budget guard, so repeated
issue lookups neither checked nor recorded rate limits. Also pins that
an issue worktree starts when the default branch exists only on the
remote.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a22af357cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/server/src/git/GitManager.ts Outdated
Comment thread apps/server/src/sourceControl/GitHubSourceControlProvider.ts
Comment thread apps/server/src/git/GitManager.ts Outdated
- Lock issue starts per project instead of server-wide, and run the
  setup script after releasing it, so a slow setup cannot block other
  projects or other issues.
- Strip the exact remote name when continuing a remote issue branch, so
  remotes with a slash in their name are found.
- Charge bare issue numbers to the repository's own GitHub host quota,
  matching the other GitHub reads.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Artic0din and others added 7 commits October 5, 2026 22:15
…ting

- A start that finishes after navigation closed the dialog no longer
  opens or prefills the originating draft.
- The issue field is disabled while the worktree is prepared, so the
  shown issue always matches the one being started.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The dialog request carries the draft it was opened on. Leaving that
  draft (Back, sidebar, another thread) drops it, while automatic
  environment selection keeps the same draft and the dialog.
- Start from issue is offered only for GitHub repositories.
- A failed start no longer lingers after the issue changes or when the
  dialog is opened again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
prepareIssueThread creates or checks out an issue branch, but unlike
the VCS worktree and ref commands it left the cached ref list alone,
so an open branch picker could miss the new branch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…hub-issues

# Conflicts:
#	apps/server/src/git/GitManager.ts
…pgrade

Upstream moved reactivity out of effect/unstable when it upgraded to
Effect 4.0.1, which broke the issue dialog's import after merging main.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ac1b23d22

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/shared/src/git.ts
Artic0din and others added 2 commits October 6, 2026 08:53
Git cannot create issue/<n>-… refs while a branch named exactly issue
exists, and its cannot-lock-ref error does not say why. Starting work
from an issue now names the blocking branch and how to rename it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: be11707ae4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/server/src/git/GitManager.ts Outdated
Comment thread apps/server/src/git/GitManager.ts Outdated
Artic0din and others added 2 commits October 6, 2026 09:04
With only origin/<base> present, git worktree add -b issue/... <path>
<base> checked out a new local <base> tracking branch instead of the
issue branch, so issue work could be committed to the default branch.
The start point is now the local branch, else origin/<base>, else a
clear error. The test now asserts the checked-out branch, not only the
commit.

Also drop --path-format from the issue lock key, which Git 2.30 and
older reject, and resolve the relative --git-common-dir output instead.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a225d8b0c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/server/src/git/GitManager.ts Outdated
Comment thread apps/server/src/git/GitManager.ts
Comment thread apps/server/src/sourceControl/GitHubSourceControlProvider.ts Outdated
…-found

- A default branch that exists only on a remote not named origin (for
  example upstream in a fork) is now used as the start point; origin
  wins when several remotes have it.
- The issue not-found message uses the transport-safe reference, so a
  pasted URL's query string or fragment is never echoed to clients.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 446c1e6470

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/server/src/git/GitManager.ts Outdated
Artic0din and others added 2 commits October 6, 2026 09:26
The suffix test on remote refs also accepted nested branches such as
aaa/releases/main, so an issue worktree could start from an unrelated
branch. Each configured remote is now checked for exactly
<remote>/<default>, origin first.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Artic0din and others added 3 commits October 6, 2026 10:18
The dialog used the VCS action's pending flag, which follows the
action's scope; automatic environment selection could change that scope
mid-start and re-enable Cancel and Start work. The dialog now owns its
starting state.

Also scope the user guide to web and desktop; mobile has no issue
start yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Automatic environment selection could move the draft while an issue
start was running. The dialog then unmounted (dropping the result) or
read its error from the new environment's action state (hiding a
failure). The dialog now keeps its lookup and start on the environment
it opened on and stays mounted. If the draft has moved, it says so
instead of attaching a worktree from another environment.

Also hide a previous lookup error while a new reference is still being
typed, and show the lookup spinner again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Artic0din
Artic0din merged commit 3a689a3 into main Oct 6, 2026
5 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

if (yield* refExists(`refs/remotes/${remote}/${baseBranch}`)) {
return `${remote}/${baseBranch}`;
}

P2 Badge Return the fully qualified remote default ref

When the default exists only as origin/main and the repository also has a valid local branch named origin/main, this verifies the unambiguous refs/remotes/origin/main but then returns the short name. GitVcsDriver.createWorktree passes that short name as the start commit; on Git 2.43 this produces warning: refname 'origin/main' is ambiguous followed by fatal: ambiguous object name: 'origin/main', so the issue worktree cannot be created. Return the same fully qualified remote ref that was verified.


if (cwdPath === existingPath || cwdPath.startsWith(`${existingPath}${path.sep}`)) {
return yield* new GitManagerError({
operation: "prepareIssueThread",
cwd: input.cwd,
detail: `${existing.name} is already checked out in the main repo. Switch the main repo off that branch to start a worktree thread.`,

P2 Badge Reuse the current linked worktree

When the registered project is itself a linked Git worktree already checked out on this issue branch, cwdPath equals or falls under existingPath, so this reports that the branch is in the main checkout and refuses the request. Git projects rooted at linked worktrees— including registered monorepo subdirectories inside one—therefore cannot use the advertised same-issue reuse behavior even though existing.worktreePath is exactly the worktree that should be returned; distinguish the primary checkout from a linked worktree before rejecting it.


if (activeProject?.environmentId !== input.environmentId) {
throw new Error(
"This project moved to another environment while the worktree was created. Close this dialog and start the issue again.",

P2 Badge Validate against the current environment after preparation

When automatic environment selection moves the draft while prepareIssueThread is pending, the in-flight handleConfirm invocation still holds the onPrepared callback from the render where the request began, and that callback captured the old activeProject. This comparison therefore sees the old environment on both sides and passes, after which the stale openOrReuseProjectDraftThread closure can attach the old environment's worktree path to the draft that has moved; read the draft's current project/environment from a ref or store when preparation completes instead of validating captured render state.

AGENTS.md reference: AGENTS.md:L75-L75

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(server): resolve GitHub issues and prepare an issue worktree thread

1 participant