Skip to content
Back to skills

Issue Links

ASecurity

Relate GitHub issues and PRs — pick the right edge type (blocked-by via GraphQL, parent/sub-issue, Closes/Fixes in PR body, plain mention) and apply it. Use when asked to link, block, depend on, make a subtask of, or close-on-merge.

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 1, 2026
developmentbashnodegitapidatabase

Works with

  • api
  • mcp

Security analysis

A100/100

Scanned September 1, 2026

npx -y skills add alunduil/alunduil-chezmoi --skill issue-links --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Issue Links?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Issue Links
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/alunduil-issue-links/badge)](https://www.skillsdirectory.com/skills/alunduil-issue-links)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: issue-links
description: Relate GitHub issues and PRs — pick the right edge type (blocked-by via GraphQL, parent/sub-issue, Closes/Fixes in PR body, plain mention) and apply it. Use when asked to link, block, depend on, make a subtask of, or close-on-merge.
---

# Issue links

Pick the *strongest accurate* relationship — but no stronger.

## Decision tree

- **Closes / Fixes / Resolves #N in PR body** — auto-closes on merge.
  Default when a PR ends an issue.
- **blocked-by / blocks** — A can't proceed or ship until B lands.
  Both are peer-sized; B is *not* a piece of A. Surfaces in the
  dependency graph and gates closing.
- **parent / sub-issue** — A is decomposition of parent B's work.
  Sub wouldn't exist on its own; parent isn't done until subs are.
  Subs roll up into parent's progress.
- **plain `#N` mention** — context only, no causal edge. Discussion,
  prior art, "see also". Default when nothing stronger fits.

The trap: reaching for parent/sub-issue when blocked-by is what's
meant, because sub-issues were the only hierarchy GitHub had for
years. Size test — peer-sized → blocked-by; smaller-than-parent →
sub-issue.

## How to apply each

### Closes / Fixes / Resolves

In the PR body or commit message:

```text
Closes #123
```

Same-repo number, or `owner/repo#123` cross-repo. Recognized verbs:
close, fix, resolve (any tense).

### blocked-by (GraphQL only — no `gh issue` flag, no REST)

Two round-trips minimum: GraphQL executes one operation per request
and `Mutation` doesn't expose `repository`, so query and mutation
can't share a document. The lookup is aliased so both IDs return in
one call (one rate-limit point), then the mutation runs.

```bash
read A_ID B_ID <<<"$(gh api graphql \
  -F owner=OWNER -F repo=REPO -F a=<A> -F b=<B> \
  -f query='
    query($owner: String!, $repo: String!, $a: Int!, $b: Int!) {
      repository(owner: $owner, name: $repo) {
        a: issue(number: $a) { id }
        b: issue(number: $b) { id }
      }
    }' --jq '.data.repository | "\(.a.id) \(.b.id)"')"

gh api graphql -f a="$A_ID" -f b="$B_ID" -f query='
  mutation($a: ID!, $b: ID!) {
    addBlockedBy(input: { issueId: $a, blockingIssueId: $b }) {
      issue { number }
      blockingIssue { number }
    }
  }'
```

Cross-repo: lift each alias above `repository` so each issue gets
its own repo selection in the same query:

```graphql
a: repository(owner: $oA, name: $rA) { issue(number: $nA) { id } }
b: repository(owner: $oB, name: $rB) { issue(number: $nB) { id } }
```

Removal: `removeBlockedBy(input: { issueId, blockingIssueId })`.
Read: `Issue.blockedBy`, `Issue.blocking`, `Issue.issueDependenciesSummary`.
Use `-f` (not `-F`) for `ID!` variables — `-F` coerces to Int/Bool.

### Parent / sub-issue

REST (no GraphQL needed). `sub_issue_id` is the sub's **database id**
(`.id` from the REST issue endpoint), not its number or node id; one
extra GET resolves it.

```bash
SUB_ID=$(gh api repos/OWNER/REPO/issues/<sub> --jq '.id')
gh api --method POST repos/OWNER/REPO/issues/<parent>/sub_issues \
  -F sub_issue_id="$SUB_ID"
```

Removal: `DELETE .../issues/<parent>/sub_issue` (singular) with the
same `sub_issue_id`. Reorder: `PATCH .../sub_issues/priority`.
Reparent: re-add with `-F replace_parent=true`. Read children:
`gh api repos/OWNER/REPO/issues/<parent>/sub_issues`. The MCP REST
tools `sub_issue_write` / `issue_read` (get_sub_issues) wrap the same
endpoints.

### Plain mention

Just `#123` in the body. No tooling.

## Procedure

1. Read both issues — what each is *for*. Don't link from the user's
   framing alone.
2. Apply the strongest accurate edge using the size test: peer-sized
   → blocked-by; smaller-than-parent → sub-issue; resolved-by-merge →
   Closes; otherwise → plain mention. If torn between two, surface;
   don't silently pick.
3. Verify it reads back: `Issue.blockedBy` / `Issue.subIssues` for
   graph edges, the PR body for Closes.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.