Gh Request

Find the next issue in 'new' status, move it to 'request', analyse the scope, and post an outline plan. Runs continuously — polls…

goodtribes-org updated 2mo ago
Claude CodeGeneric
View source ↗
# 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 @" and stop entirely.


↻ 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 with PVTI_)
  • content.number — linked issue number
  • content.repository — repo the issue lives in (e.g. goodtribes-org/kickfix)
  • projectNumber and projectNodeId — 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 # with label $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:

  • new option id<newOptionId>
  • request option id<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 # claimed — card moved to 'request'."

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:

  • kickfix
  • asylguiden.se
  • goodtribes.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.