diff --git a/docs/README.skills.md b/docs/README.skills.md index 7da25bdf..e90a64b7 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -120,7 +120,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to | [git-commit](../skills/git-commit/SKILL.md) | Execute git commit with conventional commit message analysis, intelligent staging, and message generation. Use when user asks to commit changes, create a git commit, or mentions "/commit". Supports: (1) Auto-detecting type and scope from changes, (2) Generating conventional commit messages from diff, (3) Interactive commit with optional type/scope/description overrides, (4) Intelligent file staging for logical grouping | None | | [git-flow-branch-creator](../skills/git-flow-branch-creator/SKILL.md) | Intelligent Git Flow branch creator that analyzes git status/diff and creates appropriate branches following the nvie Git Flow branching model. | None | | [github-copilot-starter](../skills/github-copilot-starter/SKILL.md) | Set up complete GitHub Copilot configuration for a new project based on technology stack | None | -| [github-issues](../skills/github-issues/SKILL.md) | Create, update, and manage GitHub issues using MCP tools. Use this skill when users want to create bug reports, feature requests, or task issues, update existing issues, add labels/assignees/milestones, or manage issue workflows. Triggers on requests like "create an issue", "file a bug", "request a feature", "update issue X", or any GitHub issue management task. | `references/templates.md` | +| [github-issues](../skills/github-issues/SKILL.md) | Create, update, and manage GitHub issues using MCP tools. Use this skill when users want to create bug reports, feature requests, or task issues, update existing issues, add labels/assignees/milestones, set issue fields (dates, priority, custom fields), set issue types, or manage issue workflows. Triggers on requests like "create an issue", "file a bug", "request a feature", "update issue X", "set the priority", "set the start date", or any GitHub issue management task. | `references/dependencies.md`
`references/issue-fields.md`
`references/issue-types.md`
`references/projects.md`
`references/sub-issues.md`
`references/templates.md` | | [go-mcp-server-generator](../skills/go-mcp-server-generator/SKILL.md) | Generate a complete Go MCP server project with proper structure, dependencies, and implementation using the official github.com/modelcontextprotocol/go-sdk. | None | | [image-manipulation-image-magick](../skills/image-manipulation-image-magick/SKILL.md) | Process and manipulate images using ImageMagick. Supports resizing, format conversion, batch processing, and retrieving image metadata. Use when working with images, creating thumbnails, resizing wallpapers, or performing batch image operations. | None | | [import-infrastructure-as-code](../skills/import-infrastructure-as-code/SKILL.md) | Import existing Azure resources into Terraform using Azure CLI discovery and Azure Verified Modules (AVM). Use when asked to reverse-engineer live Azure infrastructure, generate Infrastructure as Code from existing subscriptions/resource groups/resource IDs, map dependencies, derive exact import addresses from downloaded module source, prevent configuration drift, and produce AVM-based Terraform files ready for validation and planning across any Azure resource type. | None | diff --git a/skills/github-issues/SKILL.md b/skills/github-issues/SKILL.md index c2e88659..48b41f39 100644 --- a/skills/github-issues/SKILL.md +++ b/skills/github-issues/SKILL.md @@ -1,6 +1,6 @@ --- name: github-issues -description: 'Create, update, and manage GitHub issues using MCP tools. Use this skill when users want to create bug reports, feature requests, or task issues, update existing issues, add labels/assignees/milestones, or manage issue workflows. Triggers on requests like "create an issue", "file a bug", "request a feature", "update issue X", or any GitHub issue management task.' +description: 'Create, update, and manage GitHub issues using MCP tools. Use this skill when users want to create bug reports, feature requests, or task issues, update existing issues, add labels/assignees/milestones, set issue fields (dates, priority, custom fields), set issue types, or manage issue workflows. Triggers on requests like "create an issue", "file a bug", "request a feature", "update issue X", "set the priority", "set the start date", or any GitHub issue management task.' --- # GitHub Issues @@ -17,6 +17,11 @@ Manage GitHub issues using the `@modelcontextprotocol/server-github` MCP server. | `mcp__github__search_issues` | Search issues | | `mcp__github__add_issue_comment` | Add comments | | `mcp__github__list_issues` | List repository issues | +| `mcp__github__list_issue_types` | List available issue types for an organization | +| `mcp__github__issue_read` | Read issue details, sub-issues, comments, labels | +| `mcp__github__projects_list` | List projects, project fields, project items, status updates | +| `mcp__github__projects_get` | Get details of a project, field, item, or status update | +| `mcp__github__projects_write` | Add/update/delete project items, create status updates | ## Workflow @@ -43,8 +48,13 @@ body: structured markdown content labels: ["bug", "enhancement", "documentation", ...] assignees: ["username1", "username2"] milestone: milestone number (integer) +type: issue type name (e.g., "Bug", "Feature", "Task", "Epic") ``` +**Issue types** are organization-level metadata. Before using `type`, call `mcp__github__list_issue_types` with the org name to discover available types. If the org has no issue types configured, omit the parameter. + +**Prefer issue types over labels for categorization.** When issue types are available (e.g., Bug, Feature, Task), use the `type` parameter instead of applying equivalent labels like `bug` or `enhancement`. Issue types are the canonical way to categorize issues on GitHub. Only fall back to labels when the org has no issue types configured. + ### Title Guidelines - Start with type prefix when useful: `[Bug]`, `[Feature]`, `[Docs]` @@ -89,7 +99,7 @@ State values: `open`, `closed` "repo": "awesome-copilot", "title": "[Bug] Login page crashes when using SSO", "body": "## Description\nThe login page crashes when users attempt to authenticate using SSO.\n\n## Steps to Reproduce\n1. Navigate to login page\n2. Click 'Sign in with SSO'\n3. Page crashes\n\n## Expected Behavior\nSSO authentication should complete and redirect to dashboard.\n\n## Actual Behavior\nPage becomes unresponsive and displays error.\n\n## Environment\n- Browser: [To be filled]\n- OS: [To be filled]\n\n## Additional Context\nReported by user.", - "labels": ["bug"] + "type": "Bug" } ``` @@ -104,7 +114,8 @@ State values: `open`, `closed` "repo": "awesome-copilot", "title": "[Feature] Add dark mode support", "body": "## Summary\nAdd dark mode theme option for improved user experience and accessibility.\n\n## Motivation\n- Reduces eye strain in low-light environments\n- Increasingly expected by users\n- Improves accessibility\n\n## Proposed Solution\nImplement theme toggle with system preference detection.\n\n## Acceptance Criteria\n- [ ] Toggle switch in settings\n- [ ] Persists user preference\n- [ ] Respects system preference by default\n- [ ] All UI components support both themes\n\n## Alternatives Considered\nNone specified.\n\n## Additional Context\nHigh priority request.", - "labels": ["enhancement", "high-priority"] + "type": "Feature", + "labels": ["high-priority"] } ``` @@ -130,3 +141,15 @@ Use these standard labels when applicable: - Ask for missing critical information rather than guessing - Link related issues when known: `Related to #123` - For updates, fetch current issue first to preserve unchanged fields + +## Extended Capabilities + +The following features require REST or GraphQL APIs beyond the basic MCP tools. Each is documented in its own reference file so the agent only loads the knowledge it needs. + +| Capability | When to use | Reference | +|------------|-------------|-----------| +| Sub-issues & parent issues | Breaking work into hierarchical tasks | [references/sub-issues.md](references/sub-issues.md) | +| Issue dependencies | Tracking blocked-by / blocking relationships | [references/dependencies.md](references/dependencies.md) | +| Issue types (advanced) | GraphQL operations beyond MCP `list_issue_types` / `type` param | [references/issue-types.md](references/issue-types.md) | +| Projects V2 | Project boards, progress reports, field management | [references/projects.md](references/projects.md) | +| Issue fields | Custom metadata: dates, priority, text, numbers (private preview) | [references/issue-fields.md](references/issue-fields.md) | diff --git a/skills/github-issues/references/dependencies.md b/skills/github-issues/references/dependencies.md new file mode 100644 index 00000000..6b3b09c9 --- /dev/null +++ b/skills/github-issues/references/dependencies.md @@ -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. diff --git a/skills/github-issues/references/issue-fields.md b/skills/github-issues/references/issue-fields.md new file mode 100644 index 00000000..d60e4e49 --- /dev/null +++ b/skills/github-issues/references/issue-fields.md @@ -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 } + } +}' +``` diff --git a/skills/github-issues/references/issue-types.md b/skills/github-issues/references/issue-types.md new file mode 100644 index 00000000..f605d7b2 --- /dev/null +++ b/skills/github-issues/references/issue-types.md @@ -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` diff --git a/skills/github-issues/references/projects.md b/skills/github-issues/references/projects.md new file mode 100644 index 00000000..ce633a18 --- /dev/null +++ b/skills/github-issues/references/projects.md @@ -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 + } +} +``` diff --git a/skills/github-issues/references/sub-issues.md b/skills/github-issues/references/sub-issues.md new file mode 100644 index 00000000..96577f9d --- /dev/null +++ b/skills/github-issues/references/sub-issues.md @@ -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.