Manages GitHub issue parent-child relationships and sub-issues using REST and GraphQL APIs...
Manage GitHub issue parent-child relationships (sub-issues) using the REST and GraphQL APIs.
When invoked, help the user manage issue hierarchies by:
Understanding the request - Determine what hierarchy operation is needed:
Get issue information - If not provided, ask the user:
Execute the appropriate operation based on the request type.
Using REST API:
# Get the issue ID (not node_id) from REST API
PARENT_ID=$(gh api "repos/OWNER/REPO/issues/PARENT_NUMBER" --jq '.id')
SUB_ISSUE_ID=$(gh api "repos/OWNER/REPO/issues/SUB_NUMBER" --jq '.id')
# Add sub-issue
gh api --method POST "repos/OWNER/REPO/issues/$PARENT_ID/sub_issues" \
-f sub_issue_id="$SUB_ISSUE_ID"
Using GraphQL:
# Get node IDs
PARENT_NODE_ID=$(gh api graphql -f query='
query {
repository(owner: "OWNER", name: "REPO") {
issue(number: PARENT_NUMBER) { id }
}
}' --jq '.data.repository.issue.id')
SUB_NODE_ID=$(gh api graphql -f query='
query {
repository(owner: "OWNER", name: "REPO") {
issue(number: SUB_NUMBER) { id }
}
}' --jq '.data.repository.issue.id')
# Add sub-issue
gh api graphql -f query='
mutation {
addSubIssue(input: {
issueId: "'$PARENT_NODE_ID'"
subIssueId: "'$SUB_NODE_ID'"
}) {
issue {
number
title
}
}
}'
Using REST API:
# Get IDs
PARENT_ID=$(gh api "repos/OWNER/REPO/issues/PARENT_NUMBER" --jq '.id')
SUB_ISSUE_ID=$(gh api "repos/OWNER/REPO/issues/SUB_NUMBER" --jq '.id')
# Remove sub-issue
gh api --method DELETE "repos/OWNER/REPO/issues/$PARENT_ID/sub_issues/$SUB_ISSUE_ID"
Using GraphQL:
gh api graphql -f query='
mutation {
removeSubIssue(input: {
issueId: "'$PARENT_NODE_ID'"
subIssueId: "'$SUB_NODE_ID'"
}) {
issue {
number
title
}
}
}'
Using REST API:
gh api "repos/OWNER/REPO/issues/ISSUE_NUMBER/parent" --jq '{number: .number, title: .title}'
Using GraphQL:
gh api graphql -f query='
query {
repository(owner: "OWNER", name: "REPO") {
issue(number: PARENT_NUMBER) {
number
title
subIssues(first: 50) {
nodes {
number
title
state
}
totalCount
}
}
}
}' --jq '.data.repository.issue'
Get complete hierarchy including nested levels:
gh api graphql -f query='
query {
repository(owner: "OWNER", name: "REPO") {
issue(number: PARENT_NUMBER) {
number
title
subIssues(first: 50) {
nodes {
number
title
state
subIssues(first: 50) {
nodes {
number
title
state
}
}
}
}
}
}
}'
Change position in parent's sub-issue list:
# Move sub-issue to specific position (0-indexed)
PARENT_ID=$(gh api "repos/OWNER/REPO/issues/PARENT_NUMBER" --jq '.id')
SUB_ISSUE_ID=$(gh api "repos/OWNER/REPO/issues/SUB_NUMBER" --jq '.id')
gh api --method PATCH "repos/OWNER/REPO/issues/$PARENT_ID/sub_issues/$SUB_ISSUE_ID" \
-f position=0 # Move to first position
I_ (for GraphQL)ID confusion:
id field (integer)id field (string starting with I_)gh issue view --json id returns node_id, NOT the REST numeric IDInheritance:
Work breakdown structure:
Epic #100: Add authentication system
├─ Feature #101: Implement JWT tokens
├─ Feature #102: Add login UI
│ ├─ Task #103: Design login form
│ └─ Task #104: Add validation
└─ Feature #105: Add session management
Release planning:
Release #200: v2.0.0
├─ #201: Feature A
├─ #202: Feature B
└─ #203: Bug fixes
Milestone tracking:
Milestone #300: Q1 Goals
├─ #301: Improve performance
├─ #302: Add monitoring
└─ #303: Security audit
# Create parent Epic
EPIC_NUMBER=$(gh issue create \
--title "Add authentication system" \
--body "Epic for implementing user authentication" \
--label "epic" \
--json number --jq '.number')
# Create sub-issues
TASK1=$(gh issue create --title "Implement JWT tokens" --json number --jq '.number')
TASK2=$(gh issue create --title "Add login UI" --json number --jq '.number')
TASK3=$(gh issue create --title "Add session management" --json number --jq '.number')
# Add as sub-issues
EPIC_ID=$(gh api "repos/OWNER/REPO/issues/$EPIC_NUMBER" --jq '.id')
for task in $TASK1 $TASK2 $TASK3; do
TASK_ID=$(gh api "repos/OWNER/REPO/issues/$task" --jq '.id')
gh api --method POST "repos/OWNER/REPO/issues/$EPIC_ID/sub_issues" \
-f sub_issue_id="$TASK_ID"
done
echo "✅ Created Epic #$EPIC_NUMBER with 3 sub-tasks"
# Given an issue with checklist in body:
# - [ ] Implement JWT tokens
# - [ ] Add login UI
# - [ ] Add session management
PARENT_NUMBER=100
PARENT_ID=$(gh api "repos/OWNER/REPO/issues/$PARENT_NUMBER" --jq '.id')
# Extract checklist items and create sub-issues
gh issue view $PARENT_NUMBER --json body --jq '.body' | \
grep -E '^\s*-\s+\[ \]' | \
sed 's/^\s*-\s*\[ \]\s*//' | \
while read -r task; do
echo "Creating: $task"
ISSUE_NUM=$(gh issue create --title "$task" --json number --jq '.number')
ISSUE_ID=$(gh api "repos/OWNER/REPO/issues/$ISSUE_NUM" --jq '.id')
gh api --method POST "repos/OWNER/REPO/issues/$PARENT_ID/sub_issues" \
-f sub_issue_id="$ISSUE_ID"
done
# Display parent with all sub-issues
gh api graphql -f query='
query {
repository(owner: "OWNER", name: "REPO") {
issue(number: 100) {
number
title
subIssues(first: 50) {
nodes {
number
title
state
}
totalCount
}
}
}
}' --jq '.data.repository.issue |
"Parent: #\(.number) - \(.title)\n" +
"Sub-issues (\(.subIssues.totalCount)):\n" +
(.subIssues.nodes | map(" ├─ #\(.number) [\(.state)] \(.title)") | join("\n"))'
# Remove from old parent
OLD_PARENT_ID=$(gh api "repos/OWNER/REPO/issues/100" --jq '.id')
SUB_ISSUE_ID=$(gh api "repos/OWNER/REPO/issues/150" --jq '.id')
gh api --method DELETE "repos/OWNER/REPO/issues/$OLD_PARENT_ID/sub_issues/$SUB_ISSUE_ID"
# Add to new parent
NEW_PARENT_ID=$(gh api "repos/OWNER/REPO/issues/200" --jq '.id')
gh api --method POST "repos/OWNER/REPO/issues/$NEW_PARENT_ID/sub_issues" \
-f sub_issue_id="$SUB_ISSUE_ID"
echo "✅ Moved #150 from #100 to #200"
Common issues:
"Resource not accessible by integration"
"Issue is already a sub-issue"
"Circular dependency detected"
"Invalid issue ID"
id for REST API (not node_id)"Sub-issue limit exceeded"
When to use sub-issues:
When NOT to use sub-issues:
gh-issue-dependencies)Hierarchy design:
Combining with other features:
Sub-issues (this skill):
Dependencies (see gh-issue-dependencies skill):
These can be combined:
Epic #100: Add authentication
├─ #101: JWT tokens (blocked by #200 API schema design)
├─ #102: Login UI
└─ #103: Sessions (blocked by #101)
Works well with:
gh-issue-dependencies skill - Add blocking relationships between sub-issuesgh-project-manage skill - Track sub-issue progress in projectsgh-issue-types skill - Assign types (Epic, Feature, Task) to hierarchy levelsgit-issue-create agent - Create parent and children in one workflowAutomation ideas:
Recommended hierarchy levels:
Epic (parent) - Large feature or initiative
epicFeature (child of Epic) - Distinct deliverable
featureTask (child of Feature) - Implementation step
taskExample hierarchy:
Epic #100: User authentication system
├─ Feature #101: Add OAuth integration
├─ Feature #102: Add two-factor authentication
└─ Feature #103: Update session management