Skip to content

feat(server): agents link GitHub issues to their thread over MCP - #1441

Merged
donjor merged 1 commit into
hyprwsfrom
t3code/issue-links-mcp
Sep 30, 2026
Merged

donjor merged 1 commit into
hyprwsfrom
t3code/issue-links-mcp

Conversation

@donjor-agent

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

Copy link
Copy Markdown

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

What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

Tool Does
link_issue links by URL, or repository and number, as agent
unlink_issue removes a link; reports whether one existed
list_thread_issues the thread's links with last known state
  • Thread: always the calling token's own thread
  • Host default: the project's host when only a number is given
  • Repeat link: alreadyLinked, no error
  • Absent unlink: wasLinked: false, no error
  • Other rejections: stay failures
  • Deleted thread: not found, never a no-op
  • Stored URL: canonical issue URL only
  • Hosts: github.com or the project's host
  • Capability: rides the pull request tools' gate
  • Instruction: one line beside the pull request linking line

Upstream files change only by fork-hook lines in McpHttpServer.ts and RuntimeInstructions.ts.

Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

Checks

vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0

Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

  1. link_issue the issue URL
  2. link_issue it again
  3. list_thread_issues
  4. unlink_issue it
  5. unlink_issue it again
  6. list_thread_issues

tools-crop.png

Close conditions

Closes #1433

  • link_issue: links by URL as agent
  • unlink_issue: removes the link
  • list_thread_issues: lists the thread's links
  • Idempotent: a repeat link changes nothing
  • Scope: a call reaches only its own thread
  • Missing thread: fails, never "already linked"
Condition Evidence
link_issue "links by URL with source agent on the token's thread"
unlink_issue "unlinks a linked issue and reports a missing one as wasLinked=false"
list_thread_issues "lists the shell's links, with unknown state until the first read"
Idempotent "treats a duplicate link as alreadyLinked rather than an error"
Scope the thread comes from the invocation token, never the input
Missing thread "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found"

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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

Fork trailers

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

@rsi-software-agent rsi-software-agent Bot added the size:XL 500-999 effective changed lines (test files excluded in mixed PRs). label Sep 30, 2026
@donjor
donjor force-pushed the t3code/issue-links-mcp branch from c0f8f27 to 4dd3d5a Compare September 30, 2026 00:38
Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
@donjor
donjor force-pushed the t3code/issue-links-mcp branch from 4dd3d5a to 90b06bf Compare September 30, 2026 01:34
@donjor
donjor merged commit 21a4639 into hyprws Sep 30, 2026
9 checks passed
@donjor
donjor deleted the t3code/issue-links-mcp branch September 30, 2026 01:41
donjor added a commit that referenced this pull request Sep 30, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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 3, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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 3, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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 3, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

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 6, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 8, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 10, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor added a commit that referenced this pull request Oct 10, 2026
…CP (#1441)

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor added a commit that referenced this pull request Oct 10, 2026
…CP (#1441)

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 16, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 18, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 18, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 18, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 19, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 19, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 19, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 20, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 20, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 20, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 20, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 20, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 21, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 21, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 21, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 21, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 21, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 22, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 22, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 23, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 24, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 27, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 27, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 27, 2026
…CP (#1441)

Describe an issue task without the broad work-on phrase rejected by the upstream PR-linking policy regression. Keep the immediate issue link, exclusions, idempotence, and failure-reporting instructions unchanged.

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 27, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 08f914e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ccc7cbd fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 28, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 08f914e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ccc7cbd fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 28, 2026
## What Changed

Agents link GitHub issues to their own thread over MCP, the way they link pull requests.

| Tool | Does |
| --- | --- |
| `link_issue` | links by URL, or repository and number, as `agent` |
| `unlink_issue` | removes a link; reports whether one existed |
| `list_thread_issues` | the thread's links with last known state |

- **Thread:** always the calling token's own thread
- **Host default:** the project's host when only a number is given
- **Repeat link:** `alreadyLinked`, no error
- **Absent unlink:** `wasLinked: false`, no error
- **Other rejections:** stay failures
- **Deleted thread:** not found, never a no-op
- **Stored URL:** canonical issue URL only
- **Hosts:** github.com or the project's host
- **Capability:** rides the pull request tools' gate
- **Instruction:** one line beside the pull request linking line

Upstream files change only by `fork-hook` lines in `McpHttpServer.ts` and `RuntimeInstructions.ts`.

## Why

Agents already register the pull requests they open; the issues they work on stayed invisible to the thread.
This is layer 3 of #1430, on the link model from #1440.

## Checks

```text
vp fmt --check (changed files)                         → exit 0
vp lint (changed files)                                → exit 0
tsc --noEmit (apps/server)                             → exit 0
vp test run issues toolkit + instructions              → exit 0 (13 tests)
vp run fork:ci                                         → exit 0
```

## Evidence

A real Claude thread on this branch's dev server, told to use only its MCP tools:

1. `link_issue` the issue URL
2. `link_issue` it again
3. `list_thread_issues`
4. `unlink_issue` it
5. `unlink_issue` it again
6. `list_thread_issues`

![tools-crop.png](https://github.com/user-attachments/assets/a0e64496-99a1-4e7d-acd9-b82819cc63dc)

## Close conditions

Closes #1433

- [x] link_issue: links by URL as agent
- [x] unlink_issue: removes the link
- [x] list_thread_issues: lists the thread's links
- [x] Idempotent: a repeat link changes nothing
- [x] Scope: a call reaches only its own thread
- [x] Missing thread: fails, never "already linked"

| Condition | Evidence |
| --- | --- |
| link_issue | "links by URL with source agent on the token's thread" |
| unlink_issue | "unlinks a linked issue and reports a missing one as wasLinked=false" |
| list_thread_issues | "lists the shell's links, with unknown state until the first read" |
| Idempotent | "treats a duplicate link as alreadyLinked rather than an error" |
| Scope | the thread comes from the invocation token, never the input |
| Missing thread | "fails cleanly when the token's thread no longer exists"; "reports a thread deleted between lookup and dispatch as not found" |

## 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

No UI changes; the capture above is server evidence.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Squashes:

- 08f914e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ccc7cbd fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 5f9c06e feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 13b5837 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 8022f70 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- 05e302b fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- dda4b19 fixup! feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- b06df04 feat(server): agents link GitHub issues to their thread over MCP (#1441) (#1441)
- ead034c fix(fork): adapt fork seams to v0.0.46-nightly.20261005.2689

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 effective changed lines (test files excluded in mixed PRs).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Agents link, unlink, and list a thread's issues over MCP [✨#1430]

1 participant