ghpm-issue
PREREQUISITE: Read ../ghpm-shared/SKILL.md for prerequisites and error handling.
File a GitHub issue and add it to the project board in one step. Works mid-session (during ghpm-work) or standalone.
Arguments
/ghpm-issue — interactive: asks for title and body
/ghpm-issue <title> — uses argument as issue title, asks for optional body
Workflow
Phase 1: Setup
Startup sequence: Follow the startup sequence in ../ghpm-shared/SKILL.md. This loads config, refreshes cache if stale, and checks for stale sessions.
Extract from config:
config.project — id, owner, number, title
config.repos — eligible repositories
config.workflow — columns, field_id
config.fields — project fields with name, id, type, options
config.conventions — natural language rules (if present)
Phase 2: Gather Info
Title and body:
- If argument provided, use as title. Ask for an optional body (user can skip).
- If no argument, ask for title, then ask for optional body.
Pick repo:
- If
config.repos has one entry → use it.
- If
config.repos is empty or missing → ask the user to specify a repo in owner/repo format.
- If
config.repos has multiple entries → present a numbered list and ask.
Link to active session: Find active session per ../ghpm-shared/references/session.md (match current branch against session files). If found, prepend to the issue body:
Related to <repo>#<num>
<original body>
Phase 3: Infer Metadata
All inference is best-effort. Skip silently when no confident match exists.
Infer labels: Fetch the target repo's actual labels:
gh label list -R <repo> --json name,description --jq '.[] | "\(.name)\t\(.description)"'
Match the issue title and body against the fetched label names and descriptions (case-insensitive substring/keyword matching). Only use labels that exist on the repo — never assume a label exists.
If no labels match confidently, skip. Don't force a match.
Infer initial status: Use config.workflow.columns to determine the initial status:
- If
config.conventions.status_sync is present, interpret it for new issue context (e.g., if it describes transitions from Planned, that implies new issues start at Planned or earlier).
- Otherwise, use the first column in
config.workflow.columns as the default.
- Never hardcode a column name — always resolve from config.
Infer project fields: Iterate over config.fields entries where type is "single_select" and options is non-empty. For each field, infer the best option from the issue context (title, body, labels, repo name):
- Compare each
options[].name (case-insensitive) against the issue context for a substring or keyword match.
- If exactly one option matches confidently, use it. If ambiguous or no match, skip silently.
- When in doubt, skip rather than guess.
Phase 4: Confirm and Create
Confirm:
Prompt (create_issue): Show the resolved issue details — title, repo, labels (if any), initial status, inferred fields — and ask: "Create this issue and add to <project.title>?"
Resolve via prompts.ghpm-issue.create_issue per ../ghpm-shared/references/prompts.md.
Create issue:
gh issue create -R <repo> --title "<title>" --body "<body>" [--label <labels>]
Extract the issue URL from stdout. Then fetch the node ID:
gh issue view <url> --json number,url,id --jq '{number: .number, url: .url, nodeId: .id}'
Add to project:
gh api graphql -f query='
mutation {
addProjectV2ItemById(input: {
projectId: "<config.project.id>"
contentId: "<issue nodeId>"
}) { item { id } }
}'
Extract the project item ID for field mutations.
If this fails: The issue still exists on GitHub. Report the URL and provide the manual fallback:
Could not add to project. Add manually:
gh project item-add <config.project.number> --owner <config.project.owner> --url <issue-url>
Set status: Using the status resolved in step 6:
gh api graphql -f query='
mutation {
updateProjectV2ItemFieldValue(input: {
projectId: "<config.project.id>"
itemId: "<project item ID>"
fieldId: "<config.workflow.field_id>"
value: { singleSelectOptionId: "<resolved status column id>" }
}) { projectV2Item { id } }
}'
If this fails, continue — the item is on the board, just without a status.
Set project fields: For each field inferred in step 7, set via GraphQL (run mutations in parallel where possible):
gh api graphql -f query='
mutation {
updateProjectV2ItemFieldValue(input: {
projectId: "<config.project.id>"
itemId: "<project item ID>"
fieldId: "<field.id>"
value: { singleSelectOptionId: "<matched option.id>" }
}) { projectV2Item { id } }
}'
If a mutation fails, continue with remaining fields.
Phase 5: Output
Format per ../ghpm-shared/references/format.md:
Created #<num> "<title>" in <repo>
Project: <config.project.title> (<resolved status>)
<field.name>: <option.name> (for each field set in step 12)
URL: <issue-url>
Prompt Configuration
Per ../ghpm-shared/references/prompts.md. Config lives at prompts.ghpm-issue in .ghpm/config.json.
Action keys: create_issue.
Tips
- This skill does NOT create a work session. Use
/ghpm-work <number> after filing to start working on the new issue.
See Also
1---2name: ghpm-issue3description: File a GitHub issue and add it to the project board. Works mid-session or standalone. Reads .ghpm/config.json for repo list and project.4---56# ghpm-issue78> **PREREQUISITE:** Read `../ghpm-shared/SKILL.md` for prerequisites and error handling.910File a GitHub issue and add it to the project board in one step. Works mid-session (during `ghpm-work`) or standalone.1112## Arguments1314- `/ghpm-issue` — interactive: asks for title and body15- `/ghpm-issue <title>` — uses argument as issue title, asks for optional body1617## Workflow1819### Phase 1: Setup20211. **Startup sequence**: Follow the startup sequence in `../ghpm-shared/SKILL.md`. This loads config, refreshes cache if stale, and checks for stale sessions.2223 Extract from config:24 - `config.project` — id, owner, number, title25 - `config.repos` — eligible repositories26 - `config.workflow` — columns, field_id27 - `config.fields` — project fields with name, id, type, options28 - `config.conventions` — natural language rules (if present)2930### Phase 2: Gather Info31322. **Title and body**:33 - If argument provided, use as **title**. Ask for an optional body (user can skip).34 - If no argument, ask for **title**, then ask for optional **body**.35363. **Pick repo**:37 - If `config.repos` has **one entry** → use it.38 - If `config.repos` is **empty or missing** → ask the user to specify a repo in `owner/repo` format.39 - If `config.repos` has **multiple entries** → present a numbered list and ask.40414. **Link to active session**: Find active session per `../ghpm-shared/references/session.md` (match current branch against session files). If found, prepend to the issue body:42 ```43 Related to <repo>#<num>4445 <original body>46 ```4748### Phase 3: Infer Metadata4950All inference is best-effort. Skip silently when no confident match exists.51525. **Infer labels**: Fetch the target repo's actual labels:5354 ```bash55 gh label list -R <repo> --json name,description --jq '.[] | "\(.name)\t\(.description)"'56 ```5758 Match the issue title and body against the fetched label names and descriptions (case-insensitive substring/keyword matching). Only use labels that exist on the repo — never assume a label exists.5960 If no labels match confidently, skip. Don't force a match.61626. **Infer initial status**: Use `config.workflow.columns` to determine the initial status:63 - If `config.conventions.status_sync` is present, interpret it for new issue context (e.g., if it describes transitions from Planned, that implies new issues start at Planned or earlier).64 - Otherwise, use the first column in `config.workflow.columns` as the default.65 - Never hardcode a column name — always resolve from config.66677. **Infer project fields**: Iterate over `config.fields` entries where `type` is `"single_select"` and `options` is non-empty. For each field, infer the best option from the issue context (title, body, labels, repo name):68 - Compare each `options[].name` (case-insensitive) against the issue context for a substring or keyword match.69 - If exactly one option matches confidently, use it. If ambiguous or no match, skip silently.70 - When in doubt, skip rather than guess.7172### Phase 4: Confirm and Create73748. **Confirm**:7576 > **Prompt** (`create_issue`): Show the resolved issue details — title, repo, labels (if any), initial status, inferred fields — and ask: "Create this issue and add to <project.title>?"7778 Resolve via `prompts.ghpm-issue.create_issue` per `../ghpm-shared/references/prompts.md`.79809. **Create issue**:8182 ```bash83 gh issue create -R <repo> --title "<title>" --body "<body>" [--label <labels>]84 ```8586 Extract the issue URL from stdout. Then fetch the node ID:8788 ```bash89 gh issue view <url> --json number,url,id --jq '{number: .number, url: .url, nodeId: .id}'90 ```919210. **Add to project**:9394 ```bash95 gh api graphql -f query='96 mutation {97 addProjectV2ItemById(input: {98 projectId: "<config.project.id>"99 contentId: "<issue nodeId>"100 }) { item { id } }101 }'102 ```103104 Extract the project item ID for field mutations.105106 **If this fails:** The issue still exists on GitHub. Report the URL and provide the manual fallback:107 ```108 Could not add to project. Add manually:109 gh project item-add <config.project.number> --owner <config.project.owner> --url <issue-url>110 ```11111211. **Set status**: Using the status resolved in step 6:113114 ```bash115 gh api graphql -f query='116 mutation {117 updateProjectV2ItemFieldValue(input: {118 projectId: "<config.project.id>"119 itemId: "<project item ID>"120 fieldId: "<config.workflow.field_id>"121 value: { singleSelectOptionId: "<resolved status column id>" }122 }) { projectV2Item { id } }123 }'124 ```125126 If this fails, continue — the item is on the board, just without a status.12712812. **Set project fields**: For each field inferred in step 7, set via GraphQL (run mutations in parallel where possible):129130 ```bash131 gh api graphql -f query='132 mutation {133 updateProjectV2ItemFieldValue(input: {134 projectId: "<config.project.id>"135 itemId: "<project item ID>"136 fieldId: "<field.id>"137 value: { singleSelectOptionId: "<matched option.id>" }138 }) { projectV2Item { id } }139 }'140 ```141142 If a mutation fails, continue with remaining fields.143144### Phase 5: Output14514613. Format per `../ghpm-shared/references/format.md`:147148 ```149 Created #<num> "<title>" in <repo>150 Project: <config.project.title> (<resolved status>)151 <field.name>: <option.name> (for each field set in step 12)152 URL: <issue-url>153 ```154155## Prompt Configuration156157Per `../ghpm-shared/references/prompts.md`. Config lives at `prompts.ghpm-issue` in `.ghpm/config.json`.158159Action keys: `create_issue`.160161## Tips162163- This skill does NOT create a work session. Use `/ghpm-work <number>` after filing to start working on the new issue.164165## See Also166167- [ghpm-shared](../ghpm-shared/SKILL.md) — Prerequisites and error handling168- [ghpm-work](../ghpm-work/SKILL.md) — Start a work session on an issue169- [ghpm-suggest](../ghpm-suggest/SKILL.md) — Find what to work on next