Skip to content

feat(web): issue list narrows in place while GitHub answers - #1422

Merged
donjor merged 1 commit into
hyprwsfrom
t3code/issues-keep-list-while-loading
Sep 29, 2026
Merged

donjor merged 1 commit into
hyprwsfrom
t3code/issues-keep-list-while-loading

Conversation

@donjor-agent

@donjor-agent donjor-agent Bot commented Sep 29, 2026

Copy link
Copy Markdown

🤖 claude/anthropic claude-opus-5-5 (high)

What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

  • Held rows: the last answer for the same projects stands in
  • Narrowed: held rows filter to the new state and search terms
  • Search terms: title, number, repository, author, labels
  • Qualifiers: label:bug and the like stay GitHub's to apply
  • Marked: rows dim; the group header says what is loading
  • Ghosts: only when nothing held fits, or a first load
  • No false empty: a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; useGitHubIssueList returns carried beside data.

Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

UI Changes

Before After
switching before switching after
searching before searching after

Before: Open to All, then search; the list blanks each time

reload-before.mp4

After: same flow; rows stay and narrow in place

reload-after.mp4

Checks

tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

@donjor
donjor force-pushed the t3code/issues-keep-list-while-loading branch from e7d263c to 5039691 Compare September 29, 2026 20:50
@donjor
donjor force-pushed the t3code/issues-keep-list-while-loading branch 2 times, most recently from b08eb9f to c741d71 Compare September 29, 2026 22:54
@donjor
donjor added this pull request to stack #1436 September 29, 2026 22:55
Base automatically changed from t3code/issues-keyboard-parity to hyprws September 29, 2026 23:03
Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
@donjor
donjor force-pushed the t3code/issues-keep-list-while-loading branch from c741d71 to bc7ed5c Compare September 29, 2026 23:03
@donjor
donjor merged commit 9e44c11 into hyprws Sep 29, 2026
9 checks passed
@donjor
donjor deleted the t3code/issues-keep-list-while-loading branch September 29, 2026 23:14
donjor added a commit that referenced this pull request Sep 29, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 29, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 30, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 30, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 30, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 30, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 30, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 1, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 1, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 1, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 1, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 2, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 2, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 2, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 6, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 6, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 6, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 6, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 8, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 8, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
…1423)

> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue detail header gets the Pull Request panel's "More actions" menu.

| Item | Does |
| --- | --- |
| **Refresh** | Re-reads the issue; the trigger spins while it runs |
| **Ask a question** | Issue reference in a composer; reader types the question |
| **Explain this issue** | What it asks for, where it lands, what is risky |
| **Open on GitHub** | Opens through the host, like the PR panel |
| **Copy link** | Shows the page's copy shortcut |
| **Copy issue number** | Copies `#N` |

- **Work on this issue:** stays the one primary button
- **Beside a thread:** Ask and Explain land in that thread's composer
- **On the page:** they open a new thread on the issue's project
- **Typed text:** kept; the prompt goes below it
- **Repeat press:** no second copy
- **Shortcut label:** page only; beside a thread the shortcut copies the thread
- **Replaces:** the loose refresh and external-link icons

Prompts and the composer append are pure helpers with focused tests.

## Why

The issue panel had one real action; the PR panel has a full menu.
Asking an agent about an issue meant copying its link by hand.

## UI Changes

| Before | After |
| --- | --- |
| ![detail before](https://github.com/user-attachments/assets/748510cb-0087-4308-ab77-bb0c5ce728fa) | ![menu after](https://github.com/user-attachments/assets/a551e491-c307-4937-9979-afb5476e52b2) |

**After, Explain this issue:** a new thread holds the prompt, ready to send

![explained](https://github.com/user-attachments/assets/3e777658-8181-4292-b936-6cd5bd043cc8)

**Before:** open an issue; refresh, link and one button

https://github.com/user-attachments/assets/14086482-297c-47a2-bc7e-5fe087a14cd6

**After:** open an issue, open the menu, explain it

https://github.com/user-attachments/assets/1e775167-9fbb-4459-8744-6f68c664ef4f

## Checks

```text
tsc --noEmit (apps/web)                     → exit 0
vp test run ask logic + detail + page       → exit 0 (17 tests)
vp lint (changed files)                     → exit 0
vp run fork:ci                              → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1422.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 13, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant