Gh Request
Find the next issue in 'new' status, move it to 'request', analyse the scope, and post an outline plan. Runs continuously — polls…
# GitHub Request Planner
Find the next issue in 'new' status, move it to 'request', analyse the scope, and post an outline plan. Runs continuously — polls every 5 minutes when the queue is empty.
## Usage
/gh-request
Run from within the monorepo. The skill detects the project board and repo automatically.
## Status flow context
new → request → plan → review → apply → test ↑ Start here
## Workflow
Steps 0–1 run **once** at startup. Steps 2–14 repeat in a loop until interrupted.
### 0. Detect repo and owner
```bash
git remote get-url origin
Parse the remote URL to extract owner and repo short name. Handle both SSH (git@github.com:owner/repo.git) and HTTPS formats. Strip .git.
If there is no git remote — report "Not inside a git repository with a GitHub remote" and stop entirely.
1. Find all project boards
gh project list --owner <owner> --format json --limit 50
Collect ALL projects returned. Note each project's number and id (node ID starting with PVT_). There is no title filter — all org projects are processed.
If no projects found — report "No GitHub Project boards found under @
↻ LOOP — repeat from here after each issue or after sleeping
2. List items in 'new' status across all boards
For each project number collected in step 1, run:
gh project item-list <number> --owner <owner> --format json --limit 100
Collect all items where status equals new (case-insensitive) across all boards.
For each candidate item (prefer unassigned first), fetch its issue labels:
gh issue view <content.number> --repo <content.repository> --json labels --jq '.labels[].name'
Skip the item if any label name starts with picked-by-. Pick the first item that passes this check.
Note the item's:
id— project item node ID (starts withPVTI_)content.number— linked issue numbercontent.repository— repo the issue lives in (e.g.goodtribes-org/kickfix)projectNumberandprojectNodeId— the board this item came from (needed for step 5)
If no items in 'new' status on any board, OR all candidates have a picked-by-* label:
echo "No new issues — sleeping 5 minutes..." && sleep 300
Then go back to step 2 (do not re-run steps 0–1).
2.5. Claim the issue with a picked-by label
Get the local hostname and immediately label the issue to prevent other agents from picking it up:
PICKED_LABEL="picked-by-$(hostname)"
gh label create "$PICKED_LABEL" --repo <issueRepo> --color "f9a825" --force
gh issue edit <issueNumber> --repo <issueRepo> --add-label "$PICKED_LABEL"
Report: "Claimed issue #$PICKED_LABEL."
Store $PICKED_LABEL — you will need it when removing the label in step 7.
3. Read the issue
gh issue view <issueNumber> --repo <issueRepo> --json title,body,labels,assignees,number,url
Display the issue:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ISSUE #<number>: <title>
Repo: <issueRepo>
URL: <url>
Labels: <labels or "none">
Assignees: <assignees or "none">
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
<body>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4. Discover Status field IDs
gh project field-list <number> --owner <owner> --format json
Find the field named Status. Note its id as <statusFieldId>. From its options array note:
newoptionid→<newOptionId>requestoptionid→<requestOptionId>
Match option names case-insensitively.
5. Move card to 'request'
gh project item-edit \
--id <itemNodeId> \
--field-id <statusFieldId> \
--project-id <projectNodeId> \
--single-select-option-id <requestOptionId>
If this fails — report the error and stop.
Report: "Issue #
6. Identify and validate the sub-project
Analyze the issue title and body to determine which sub-project it targets. The only valid values are exactly:
kickfixasylguiden.segoodtribes.org
Then verify the directory actually exists in the monorepo:
ls /home/mattias/projects/goodtribes.org/<candidate>/
If the directory is missing — the label is invalid regardless of what the issue says.
If the sub-project cannot be determined with confidence, OR the directory does not exist:
Write the rejection to a temp file and post it:
cat > /tmp/gh-reject.md << 'EOF'
## Missing project label
This issue could not be linked to a known sub-project. Before planning can begin, the issue must be labelled with exactly one of:
- `kickfix`
- `asylguiden.se`
- `goodtribes.org`
*Card returned to new.*
EOF
gh issue comment <issueNumber> --repo <issueRepo> --body-file /tmp/gh-reject.md
rm /tmp/gh-reject.md
Move card back to new:
gh project item-edit \
--id <itemNodeId> \
--field-id <statusFieldId> \
--project-id <projectNodeId> \
--single-select-option-id <newOptionId>
Report: "Could not identify sub-project — card returned to new." and stop.
If confirmed: note <subProject> as the validated label and continue.
7. Tag the issue with labels
gh label create "<subProject>" --repo <issueRepo> --color "0075ca" --force
gh label create "request" --repo <issueRepo> --color "e4e669" --force
gh issue edit <issueNumber> --repo <issueRepo> --add-label "<subProject>,request" --remove-label "$PICKED_LABEL"
Do not stop if label creation fails — report a warning and continue.
8. Read codebase context
Read the root CLAUDE.md for overall stack context:
cat /home/mattias/projects/goodtribes.org/CLAUDE.md
Map the sub-project label to its local path and read its context:
| Label | Local path |
|---|---|
kickfix |
kickfix/ |
asylguiden.se |
asylguiden.se/ |
goodtribes.org |
goodtribes.org/ |
cat /home/mattias/projects/goodtribes.org/<subProjectPath>/CLAUDE.md 2>/dev/null
cat /home/mattias
Maintain Gh Request?
Let people know it's listed here — add the badge (live metrics, light/dark aware) or a plain link to your README or docs.
[Gh Request on getagentictools](https://getagentictools.com/loops/goodtribes-org-github-request-planner?ref=badge) npx agentictools info loops/goodtribes-org-github-request-planner The second line is the CLI lookup for this page — handy in READMEs and docs.