Add sub-issues, issue types, projects, and issue fields guidance to github-issues skill (#884)

* Add issue fields, issue types, and list_issue_types to github-issues skill

- Add list_issue_types to available MCP tools table
- Add type parameter to optional parameters with guidance
- Expand issue types section: MCP tools (preferred) + GraphQL (advanced)
- Document org-level type discovery, create/update with type, GraphQL mutations
- Add issue fields section: discover, read, set via GraphQL
- Note required GraphQL-Features headers (issue_fields, issue_types)
- Update skill description to mention fields, types, dates, priority

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add Projects V2 guidance to github-issues skill

Include MCP tools (projects_list, projects_get, projects_write) and
GraphQL examples for project item management.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add sub-issues section, move issue fields to end with preview note

- Add Sub-Issues and Parent Issues section (MCP, REST, GraphQL)
- Add issue_read tool to MCP tools table
- Move Issue Fields to last section with private preview callout
- Link to community discussion for requesting access

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Prefer issue types over labels for categorization

Update guidance and examples to use type parameter (Bug, Feature)
instead of equivalent labels when issue types are available.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Prefer issue fields over project fields for metadata

Issue fields live on the issue and travel across projects.
Project fields are scoped to a single project.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add issue dependencies (blocked by/blocking) section

Covers REST endpoints (list, add, remove) and GraphQL
(blockedBy, blocking, issueDependenciesSummary, mutations).
Also documents tracked issues read-only fields.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add project discovery workflow for progress reports

Teach agents how to find projects by name, discover fields
and iterations, paginate items, and build status breakdowns.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Generate updated skill listing after SKILL.md changes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Split skill into reference files per reviewer feedback

Move sub-issues, dependencies, issue types, projects, and issue fields
into separate references/ files. Main SKILL.md now contains core MCP
workflow and a capability table pointing to each reference. This way
the agent only loads the knowledge it needs for the specific task.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Tadas Labudis
2026-03-05 11:10:11 +00:00
committed by GitHub
parent 0d4b3286be
commit 164b6eb268
7 changed files with 542 additions and 4 deletions

View File

@@ -0,0 +1,71 @@
# Issue Dependencies (Blocked By / Blocking)
Dependencies let you mark that an issue is blocked by another issue. This creates a formal dependency relationship visible in the UI and trackable via API. No MCP tools exist for dependencies; use REST or GraphQL directly.
## Using REST API
**List issues blocking this issue:**
```
GET /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by
```
**Add a blocking dependency:**
```
POST /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by
Body: { "issue_id": 12345 }
```
The `issue_id` is the numeric issue **ID** (not the issue number).
**Remove a blocking dependency:**
```
DELETE /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by/{issue_id}
```
## Using GraphQL
**Read dependencies:**
```graphql
{
repository(owner: "OWNER", name: "REPO") {
issue(number: 123) {
blockedBy(first: 10) { nodes { number title state } }
blocking(first: 10) { nodes { number title state } }
issueDependenciesSummary { blockedBy blocking totalBlockedBy totalBlocking }
}
}
}
```
**Add a dependency:**
```graphql
mutation {
addBlockedBy(input: {
issueId: "BLOCKED_ISSUE_NODE_ID"
blockingIssueId: "BLOCKING_ISSUE_NODE_ID"
}) {
blockedByIssue { number title }
}
}
```
**Remove a dependency:**
```graphql
mutation {
removeBlockedBy(input: {
issueId: "BLOCKED_ISSUE_NODE_ID"
blockingIssueId: "BLOCKING_ISSUE_NODE_ID"
}) {
blockedByIssue { number title }
}
}
```
## Tracked issues (read-only)
Task-list tracking relationships are available via GraphQL as read-only fields:
- `trackedIssues(first: N)` - issues tracked in this issue's task list
- `trackedInIssues(first: N)` - issues whose task lists reference this issue
These are set automatically when issues are referenced in task lists (`- [ ] #123`). There are no mutations to manage them.

View File

@@ -0,0 +1,127 @@
# Issue Fields (GraphQL, Private Preview)
> **Private preview:** Issue fields are currently in private preview. Request access at https://github.com/orgs/community/discussions/175366
Issue fields are custom metadata (dates, text, numbers, single-select) defined at the organization level and set per-issue. They are separate from labels, milestones, and assignees. Common examples: Start Date, Target Date, Priority, Impact, Effort.
**Important:** All issue field queries and mutations require the `GraphQL-Features: issue_fields` HTTP header. Without it, the fields are not visible in the schema.
**Prefer issue fields over project fields.** When you need to set metadata like dates, priority, or status on an issue, use issue fields (which live on the issue itself) rather than project fields (which live on a project item). Issue fields travel with the issue across projects and views, while project fields are scoped to a single project. Only use project fields when issue fields are not available or when the field is project-specific (e.g., sprint iterations).
## Discovering available fields
Fields are defined at the org level. List them before trying to set values:
```graphql
# Header: GraphQL-Features: issue_fields
{
organization(login: "OWNER") {
issueFields(first: 30) {
nodes {
__typename
... on IssueFieldDate { id name }
... on IssueFieldText { id name }
... on IssueFieldNumber { id name }
... on IssueFieldSingleSelect { id name options { id name color } }
}
}
}
}
```
Field types: `IssueFieldDate`, `IssueFieldText`, `IssueFieldNumber`, `IssueFieldSingleSelect`.
For single-select fields, you need the option `id` (not the name) to set values.
## Reading field values on an issue
```graphql
# Header: GraphQL-Features: issue_fields
{
repository(owner: "OWNER", name: "REPO") {
issue(number: 123) {
issueFieldValues(first: 20) {
nodes {
__typename
... on IssueFieldDateValue {
value
field { ... on IssueFieldDate { id name } }
}
... on IssueFieldTextValue {
value
field { ... on IssueFieldText { id name } }
}
... on IssueFieldNumberValue {
value
field { ... on IssueFieldNumber { id name } }
}
... on IssueFieldSingleSelectValue {
name
color
field { ... on IssueFieldSingleSelect { id name } }
}
}
}
}
}
}
```
## Setting field values
Use `setIssueFieldValue` to set one or more fields at once. You need the issue's node ID and the field IDs from the discovery query above.
```graphql
# Header: GraphQL-Features: issue_fields
mutation {
setIssueFieldValue(input: {
issueId: "ISSUE_NODE_ID"
issueFields: [
{ fieldId: "IFD_xxx", dateValue: "2026-04-15" }
{ fieldId: "IFT_xxx", textValue: "some text" }
{ fieldId: "IFN_xxx", numberValue: 3.0 }
{ fieldId: "IFSS_xxx", singleSelectOptionId: "OPTION_ID" }
]
}) {
issue { id title }
}
}
```
Each entry in `issueFields` takes a `fieldId` plus exactly one value parameter:
| Field type | Value parameter | Format |
|-----------|----------------|--------|
| Date | `dateValue` | ISO 8601 date string, e.g. `"2026-04-15"` |
| Text | `textValue` | String |
| Number | `numberValue` | Float |
| Single select | `singleSelectOptionId` | ID from the field's `options` list |
To clear a field value, set `delete: true` instead of a value parameter.
## Workflow for setting fields
1. **Discover fields** - query the org's `issueFields` to get field IDs and option IDs
2. **Get the issue node ID** - from `repository.issue.id`
3. **Set values** - call `setIssueFieldValue` with the issue node ID and field entries
4. **Batch when possible** - multiple fields can be set in a single mutation call
## Example: Set dates and priority on an issue
```bash
gh api graphql \
-H "GraphQL-Features: issue_fields" \
-f query='
mutation {
setIssueFieldValue(input: {
issueId: "I_kwDOxxx"
issueFields: [
{ fieldId: "IFD_startDate", dateValue: "2026-04-01" }
{ fieldId: "IFD_targetDate", dateValue: "2026-04-30" }
{ fieldId: "IFSS_priority", singleSelectOptionId: "OPTION_P1" }
]
}) {
issue { id title }
}
}'
```

View File

@@ -0,0 +1,72 @@
# Issue Types (Advanced GraphQL)
Issue types (Bug, Feature, Task, Epic, etc.) are defined at the **organization** level and inherited by repositories. They categorize issues beyond labels.
For basic usage, the MCP tools handle issue types natively. Call `mcp__github__list_issue_types` to discover types, and pass `type: "Bug"` to `mcp__github__create_issue` or `mcp__github__update_issue`. This reference covers advanced GraphQL operations.
## GraphQL Feature Header
All GraphQL issue type operations require the `GraphQL-Features: issue_types` HTTP header.
## List types (org or repo level)
```graphql
# Header: GraphQL-Features: issue_types
{
organization(login: "OWNER") {
issueTypes(first: 20) {
nodes { id name color description isEnabled }
}
}
}
```
Types can also be listed per-repo via `repository.issueTypes` or looked up by name via `repository.issueType(name: "Bug")`.
## Read an issue's type
```graphql
# Header: GraphQL-Features: issue_types
{
repository(owner: "OWNER", name: "REPO") {
issue(number: 123) {
issueType { id name color }
}
}
}
```
## Set type on an existing issue
```graphql
# Header: GraphQL-Features: issue_types
mutation {
updateIssueIssueType(input: {
issueId: "ISSUE_NODE_ID"
issueTypeId: "IT_xxx"
}) {
issue { id issueType { name } }
}
}
```
## Create issue with type
```graphql
# Header: GraphQL-Features: issue_types
mutation {
createIssue(input: {
repositoryId: "REPO_NODE_ID"
title: "Fix login bug"
issueTypeId: "IT_xxx"
}) {
issue { id number issueType { name } }
}
}
```
To clear the type, set `issueTypeId` to `null`.
## Available colors
`GRAY`, `BLUE`, `GREEN`, `YELLOW`, `ORANGE`, `RED`, `PINK`, `PURPLE`

View File

@@ -0,0 +1,126 @@
# Projects V2
GitHub Projects V2 is managed via GraphQL. The MCP server provides three tools that wrap the GraphQL API, so you typically don't need raw GraphQL.
## Using MCP tools (preferred)
**List projects:**
Call `mcp__github__projects_list` with `method: "list_projects"`, `owner`, and `owner_type` ("user" or "organization").
**List project fields:**
Call `mcp__github__projects_list` with `method: "list_project_fields"` and `project_number`.
**List project items:**
Call `mcp__github__projects_list` with `method: "list_project_items"` and `project_number`.
**Add an issue/PR to a project:**
Call `mcp__github__projects_write` with `method: "add_project_item"`, `project_id` (node ID), and `content_id` (issue/PR node ID).
**Update a project item field value:**
Call `mcp__github__projects_write` with `method: "update_project_item"`, `project_id`, `item_id`, `field_id`, and `value` (object with one of: `text`, `number`, `date`, `singleSelectOptionId`, `iterationId`).
**Delete a project item:**
Call `mcp__github__projects_write` with `method: "delete_project_item"`, `project_id`, and `item_id`.
## Workflow for project operations
1. **Find the project** - use `projects_list` with `list_projects` to get the project number and node ID
2. **Discover fields** - use `projects_list` with `list_project_fields` to get field IDs and option IDs
3. **Find items** - use `projects_list` with `list_project_items` to get item IDs
4. **Mutate** - use `projects_write` to add, update, or delete items
## Project discovery for progress reports
When a user asks for a progress update on a project (e.g., "Give me a progress update for Project X"), follow this workflow:
1. **Search by name** - call `projects_list` with `list_projects` and scan results for a title matching the user's query. Project names are often informal, so match flexibly (e.g., "issue fields" matches "Issue fields" or "Issue Fields and Types").
2. **Discover fields** - call `projects_list` with `list_project_fields` to find the Status field (its options tell you the workflow stages) and any Iteration field (to scope to the current sprint).
3. **Get all items** - call `projects_list` with `list_project_items`. For large projects (100+ items), paginate through all pages. Each item includes its field values (status, iteration, assignees).
4. **Build the report** - group items by Status field value and count them. For iteration-based projects, filter to the current iteration first. Present a breakdown like:
```
Project: Issue Fields (Iteration 42, Mar 2-8)
15 actionable items:
🎉 Done: 4 (27%)
In Review: 3
In Progress: 3
Ready: 2
Blocked: 2
```
5. **Add context** - if items have sub-issues, include `subIssuesSummary` counts. If items have dependencies, note blocked items and what blocks them.
**Tip:** For org-level projects, use GraphQL with `organization.projectsV2(first: 20, query: "search term")` to search by name directly, which is faster than listing all projects.
## Using GraphQL directly (advanced)
Required scope: `read:project` for queries, `project` for mutations.
**Find a project:**
```graphql
{
organization(login: "ORG") {
projectV2(number: 5) { id title }
}
}
```
**List fields (including single-select options):**
```graphql
{
node(id: "PROJECT_ID") {
... on ProjectV2 {
fields(first: 20) {
nodes {
... on ProjectV2Field { id name }
... on ProjectV2SingleSelectField { id name options { id name } }
... on ProjectV2IterationField { id name configuration { iterations { id startDate } } }
}
}
}
}
}
```
**Add an item:**
```graphql
mutation {
addProjectV2ItemById(input: {
projectId: "PROJECT_ID"
contentId: "ISSUE_OR_PR_NODE_ID"
}) {
item { id }
}
}
```
**Update a field value:**
```graphql
mutation {
updateProjectV2ItemFieldValue(input: {
projectId: "PROJECT_ID"
itemId: "ITEM_ID"
fieldId: "FIELD_ID"
value: { singleSelectOptionId: "OPTION_ID" }
}) {
projectV2Item { id }
}
}
```
Value accepts one of: `text`, `number`, `date`, `singleSelectOptionId`, `iterationId`.
**Delete an item:**
```graphql
mutation {
deleteProjectV2Item(input: {
projectId: "PROJECT_ID"
itemId: "ITEM_ID"
}) {
deletedItemId
}
}
```

View File

@@ -0,0 +1,119 @@
# Sub-Issues and Parent Issues
Sub-issues let you break down work into hierarchical tasks. Each parent issue can have up to 100 sub-issues, nested up to 8 levels deep. Sub-issues can span repositories within the same owner.
## Using MCP tools
**List sub-issues:**
Call `mcp__github__issue_read` with `method: "get_sub_issues"`, `owner`, `repo`, and `issue_number`.
**Create an issue as a sub-issue:**
There is no MCP tool for creating sub-issues directly. Use REST or GraphQL (see below).
## Using REST API
**List sub-issues:**
```
GET /repos/{owner}/{repo}/issues/{issue_number}/sub_issues
```
**Get parent issue:**
```
GET /repos/{owner}/{repo}/issues/{issue_number}/parent
```
**Add an existing issue as a sub-issue:**
```
POST /repos/{owner}/{repo}/issues/{issue_number}/sub_issues
Body: { "sub_issue_id": 12345 }
```
The `sub_issue_id` is the numeric issue **ID** (not the issue number). Get it from the issue's `id` field in any API response.
To move a sub-issue that already has a parent, add `"replace_parent": true`.
**Remove a sub-issue:**
```
DELETE /repos/{owner}/{repo}/issues/{issue_number}/sub_issue
Body: { "sub_issue_id": 12345 }
```
**Reprioritize a sub-issue:**
```
PATCH /repos/{owner}/{repo}/issues/{issue_number}/sub_issues/priority
Body: { "sub_issue_id": 6, "after_id": 5 }
```
Use `after_id` or `before_id` to position the sub-issue relative to another.
## Using GraphQL
**Read parent and sub-issues:**
```graphql
{
repository(owner: "OWNER", name: "REPO") {
issue(number: 123) {
parent { number title }
subIssues(first: 50) {
nodes { number title state }
}
subIssuesSummary { total completed percentCompleted }
}
}
}
```
**Add a sub-issue:**
```graphql
mutation {
addSubIssue(input: {
issueId: "PARENT_NODE_ID"
subIssueId: "CHILD_NODE_ID"
}) {
issue { id }
subIssue { id number title }
}
}
```
You can also use `subIssueUrl` instead of `subIssueId` (pass the issue's HTML URL). Add `replaceParent: true` to move a sub-issue from another parent.
**Create an issue directly as a sub-issue:**
```graphql
mutation {
createIssue(input: {
repositoryId: "REPO_NODE_ID"
title: "Implement login validation"
parentIssueId: "PARENT_NODE_ID"
}) {
issue { id number }
}
}
```
**Remove a sub-issue:**
```graphql
mutation {
removeSubIssue(input: {
issueId: "PARENT_NODE_ID"
subIssueId: "CHILD_NODE_ID"
}) {
issue { id }
}
}
```
**Reprioritize a sub-issue:**
```graphql
mutation {
reprioritizeSubIssue(input: {
issueId: "PARENT_NODE_ID"
subIssueId: "CHILD_NODE_ID"
afterId: "OTHER_CHILD_NODE_ID"
}) {
issue { id }
}
}
```
Use `afterId` or `beforeId` to position relative to another sub-issue.