github-issues
SkillAI & modelsWire the PureCutCNC GitHub workflow — create issues, set the org-level Priority field (R1), add board cards and set Status/Size/Area, move cards through the lifecycle, and open PRs. Use whenever AGENTS.md requires GitHub issue/board/PR mechanics, instead of re-discovering the GraphQL/REST calls each time.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the github-issues skill
What this skill tells your AI
The instructions your AI receives, as published by purecutcnc/purecutcnc in .agents/skills/github-issues/SKILL.md and read by ahel’s review.
Encodes the GitHub mechanics behind AGENTS.md §"Workflow: Issue → Plan →
Approve → Implement → PR" and §"The Backlog Contract". AGENTS.md is
authoritative for policy (R1–R5, caps, decay, fast lane); this skill is only
the how — the exact commands, IDs, and pitfalls. It exists because every one
of these calls was re-discovered from scratch on #524/#535/#536, at a cost of
several agent turns each.
Load it (or read it by path) before doing any of: gh issue create, board
wiring, Priority, status moves, PR opening. Then verify after every mutation
— mutation success is not delivery.
The environment
- Repo:
PureCutCNC/purecutcnc - Project board: org
PureCutCNC, project #1 (node idPVT_kwDOEEztyc4Bbqk-) - Org-level issue fields (native, set per-issue):
Priority(R1),Start date,Target date,Effort - Board fields:
Status,Size,Area, plus read-only/derived ones
Current IDs (fast path)
Verify with the discovery queries below if a mutation fails; IDs survive until someone edits the fields, which is rare.
| Board field | field id | options |
|---|---|---|
| Status | PVTSSF_lADOEEztyc4Bbqk-zhWZisQ | Backlog f75ad846, Ready e18bf179, In progress 47fc9ee4, In review aba860b9, Done 98236657 |
| Size | PVTSSF_lADOEEztyc4Bbqk-zhWZi5g | XS 911790be, S b277fb01, M 86db8eb3, L 853c8207, XL 2d0801e2 |
| Area | PVTSSF_lADOEEztyc4Bbqk-zhWZltM | vcarve 9741291f, export 05ad4b5d, simulation fa63671b, tablet-ux 12689f8a, desktop cd7286f9, core b4b71171, ui 21d55d78, toolpath 37ad0723, i18n 12bb2556, theme 56423e0d, converters 083dd6f4 |
| Org issue field | field id | options |
|---|---|---|
| Priority | IFSS_kgDOAnL9vg | Urgent IFSSO_kgDOBEkkJg, High IFSSO_kgDOBEkkJw, Medium IFSSO_kgDOBEkkKA, Low IFSSO_kgDOBEkkKQ |
Area guidance: engine/toolpath → toolpath, canvas/panels → ui, palette →
theme, gates/process/agent harness → core, desktop → desktop.
Recipe: file an issue end-to-end (create → board → Priority)
-
Create (REST, cheap):
gh issue create --title "…" --body "…" --label bug # or enhancement/process/… -
Wire board + Priority (GraphQL, one batch). Set
N, the issue number, and the field values, then paste:python3 - <<'EOF' import json, subprocess def gql(query, **vars): p = subprocess.run(['gh','api','graphql','-f',f'query={query}', *[f'-F{k}={v}' for k,v in vars.items()]], capture_output=True, text=True) if p.returncode: raise SystemExit(p.stderr) return json.loads(p.stdout) N = 999 # the issue number STATUS = ('PVTSSF_lADOEEztyc4Bbqk-zhWZisQ', 'f75ad846') # Backlog SIZE = ('PVTSSF_lADOEEztyc4Bbqk-zhWZi5g', 'b277fb01') # S AREA = ('PVTSSF_lADOEEztyc4Bbqk-zhWZltM', '21d55d78') # ui PRIO = ('IFSS_kgDOAnL9vg', 'IFSSO_kgDOBEkkKA') # Medium r = gql('query($n:Int!){ repository(owner:"PureCutCNC",name:"purecutcnc"){ issue(number:$n){ id } } }', n=N) issue_id = r['data']['repository']['issue']['id'] PROJECT = 'PVT_kwDOEEztyc4Bbqk-' r = gql('mutation($p:ID!,$c:ID!){ addProjectV2ItemById(input:{projectId:$p,contentId:$c}){ item{ id } } }', p=PROJECT, c=issue_id) item_id = r['data']['addProjectV2ItemById']['item']['id'] for field, value in (STATUS, SIZE, AREA): gql('mutation($p:ID!,$i:ID!,$f:ID!,$v:String!){ updateProjectV2ItemFieldValue(input:{' 'projectId:$p,itemId:$i,fieldId:$f,value:{singleSelectOptionId:$v}}){ clientMutationId } }', p=PROJECT, i=item_id, f=field, v=value) gql('mutation($i:ID!,$f:ID!,$v:ID!){ setIssueFieldValue(input:{issueId:$i,' 'issueFields:[{fieldId:$f,singleSelectOptionId:$v}]}){ clientMutationId } }', i=issue_id, f=PRIO[0], v=PRIO[1]) print('wired', item_id) EOF -
Verify (never skip — a mutation can 404 silently in a script):
gh api repos/PureCutCNC/purecutcnc/issues/N --jq '.issue_field_values[] | select(.issue_field_name=="Priority") | .single_select_option.name'Board card fields — item id via the issue (cheaper than paginating items):
gh api graphql -f query='query($n:Int!){ repository(owner:"PureCutCNC",name:"purecutcnc"){ issue(number:$n){ projectItems(first:5){ nodes{ id } } } } }' -F n=N gh api graphql -f query='query($i:ID!){ node(id:$i){ ... on ProjectV2Item { fieldValues(first:10){ nodes{ ... on ProjectV2ItemFieldSingleSelectValue { field{... on ProjectV2FieldCommon{name}} name } } } } } }' -F i='ITEM_ID'
Priority — the exact shape that costs discovery
setIssueFieldValue takes issueFields: [{ fieldId, singleSelectOptionId }].
The per-item nesting is required — passing fieldId/singleSelectOptionId at
the mutation top level fails validation. There is no REST endpoint for
setting org issue fields; only read them via REST (.issue_field_values, used
by scripts/backlog-hygiene.ts). Priority is the native org issue field,
not a board field — do not set it through updateProjectV2ItemFieldValue.
The two mutations disagree on the type of singleSelectOptionId, and the
same option id therefore needs a different variable declaration in each:
| Mutation | Declare as |
|---|---|
updateProjectV2ItemFieldValue (board fields) | $v:String! |
setIssueFieldValue (org issue fields) | $v:ID! |
Getting it wrong fails at validation, before any network effect, with
Type mismatch on variable $v and argument singleSelectOptionId (String! / ID).
Harmless but it costs a turn — and in the batched recipe above it aborts the
script after Status/Size/Area are already set, so re-running the whole block
is safe but only Priority is actually missing.
Board item lookup
- Preferred:
repository.issue(number).projectItems(shown above) — one cheap query, no pagination. - Fallback: paginate
organization.projectV2.items(first:100, after:)with cursors.gh project item-listdefaults to 30 items per page and misleads by truncation — the card for a new issue lands at the end of the list, past the default page.
Status lifecycle
Backlog (on file) → Ready (after plan approval) → In progress (implementing) →
In review (PR open) → Done (merge; auto). Move with
updateProjectV2ItemFieldValue and the Status option ids above. Don't leave a
card in the wrong state: gh pr view --json ... ≠ board state.
PR mechanics
gh pr create --title … --body …withCloses #NNin the body (merging auto-closes and moves the card to Done).- Label
fast-laneonly whennpm run check:fast-laneis green; thefast-lane-guardCI job re-checks every labeled PR and blocks merge if red. - Rebase onto
origin/mainbefore opening and again if main moves (git fetch origin && git rebase origin/main, re-runnpm run build). gh pr checks NNreporting "no checks reported" means the branch conflicts — unverified, not pending (AGENTS.md §Git & Branching).
Rate limits — shared, and they bite
- REST and GraphQL are separate 5000/hr pools, shared by every agent running on the same account. A busy repo day exhausts GraphQL while REST is fine — observed on this account.
- Check first:
gh api rate_limit --jq '.resources.core.remaining, .resources.graphql'. - GraphQL resets at
resetAt(query it); wait or fall back to REST, which covers issue create/view/edit/label and PR operations. - Batch reads into one GraphQL query; never poll GraphQL in a loop — that is how a pool dies mid-task.
Gotchas
gh issue edit --add-label/--remove-labelfor labels; labels used here:bug,enhancement,process,performance,documentation,external-report,needs-priority(automatic),stale,backlog-digest,fast-lane.issueFieldsonOrganizationis a GraphQL union — direct field selection fails; use inline fragments (... on IssueFieldSingleSelectetc.).- Some
fieldValuesnodes are not single-select (title text, derived fields) — filter on the fragment before readingname. - After any wiring, re-check the card fields; setting a field on the wrong item id succeeds silently (happened once: 535 vs 536).
Signals
- GitHub stars
- 80
- Forks
- 5
- Last commit
- Sep 2026
ahel review
S4info
community integration — published by purecutcnc, not github
Automated review, not a security audit. Ruleset v1.
Advanced
- Catalog kind
- skill
- Gateway key
github-issues-purecutcnc- Source
- github.com/purecutcnc/purecutcnc