Gh Plan
Find an issue in the 'plan' stage, read the actual codebase, write a detailed implementation plan, and move the card to 'review'.…
# GitHub Plan Writer
Find an issue in the 'plan' stage, read the actual codebase, write a detailed implementation plan, and move the card to 'review'. Runs continuously — polls every 5 minutes when the queue is empty.
## Usage
/gh-plan
Run from the monorepo root (`~/projects/goodtribes.org`). The skill detects the project board and target sub-project automatically.
## Status flow context
new → request → plan → review → apply → test ↑ You are here
Issues arrive in 'plan' after a human approves the outline written by `/gh-request`. This skill writes the full file-level implementation plan and moves the card to 'review' for final human sign-off before implementation begins.
## Workflow
Step 0 runs **once** at startup. Steps 1–11 repeat in a loop until interrupted.
### 0. Find all project boards
```bash
gh project list --owner goodtribes-org --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" and stop entirely.
↻ LOOP — repeat from here after each issue or after sleeping
1. List items in 'plan' status across all boards
For each project number collected in step 0, run:
gh project item-list <number> --owner goodtribes-org --format json --limit 100
Collect all items where status equals plan (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— the repo the issue lives in (e.g.goodtribes-org/kickfix)projectNumberandprojectNodeId— the board this item came from (needed for step 9)
If no items in 'plan' status on any board, OR all candidates have a picked-by-* label:
echo "No issues in plan — sleeping 5 minutes..." && sleep 300
Then go back to step 1 (do not re-run step 0).
1.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 10.
2. Claim the item — move to 'plan' (keep status, set assignee context)
Look up the Status field and option IDs:
gh project field-list <number> --owner goodtribes-org --format json
Note:
- Status field
id→<statusFieldId>(starts withPVTSSF_) - Option
review→<reviewOptionId>
The card stays at plan while you work. You will move it to review only after the plan comment is posted successfully.
3. Read the issue
gh issue view <issueNumber> --repo <issueRepo> --json title,body,labels,number,url,comments
Display the issue:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ISSUE #<number>: <title>
Repo: <issueRepo>
URL: <url>
Labels: <labels>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
<body>
PREVIOUS COMMENTS:
<comments — include the gh-request outline if present>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Read both the original request (body) and any existing plan outline posted by /gh-request (in comments). The outline is the starting point — the goal here is to expand it into a precise, file-level plan.
4. Validate the sub-project label
Check the issue labels for exactly one of these values:
kickfixasylguiden.segoodtribes.org
Then verify the directory exists in the monorepo:
ls /home/mattias/projects/goodtribes.org/<label>/
If no valid label is present, OR the directory does not exist — reject the issue:
Write the rejection comment to a temp file and post it:
cat > /tmp/gh-reject.md << 'EOF'
## Missing or invalid project label
This issue cannot be planned because it has no valid sub-project label. `/gh-plan` only processes issues labelled with an existing project:
- `kickfix`
- `asylguiden.se`
- `goodtribes.org`
Please add the correct label and move the card back to **plan** when ready.
*Card returned to request.*
EOF
gh issue comment <issueNumber> --repo <issueRepo> --body-file /tmp/gh-reject.md
rm /tmp/gh-reject.md
Move card back to request:
gh project item-edit \
--id <itemNodeId> \
--field-id <statusFieldId> \
--project-id <projectNodeId> \
--single-select-option-id <requestOptionId>
Look up requestOptionId from gh project field-list if not already known — it is the Status option named request.
Update labels:
gh issue edit <issueNumber> --repo <issueRepo> --remove-label "plan" --add-label "request"
Report: "Issue #
If valid: note <subProject> and <localPath> and continue.
5. Identify the target sub-project path
Map the validated label to its local source path:
| Label | Local path |
|---|---|
kickfix |
kickfix/ |
asylguiden.se |
asylguiden.se/ |
goodtribes.org |
goodtribes.org/ |
Report: "Target sub-project: <localPath>"
6. Read the codebase
Read the sub-project's documentation and structure first:
cat /home/mattias/projects/goodtribes.org/<localPath>/CLAUDE.md 2>/dev/null
cat /home/mattias/projects/goodtribes.org/CLAUDE.md
Then explore the relevant source files. Use the issue body and the `gh- ```
Maintain Gh Plan?
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 Plan on getagentictools](https://getagentictools.com/loops/goodtribes-org-github-plan-writer?ref=badge) npx agentictools info loops/goodtribes-org-github-plan-writer The second line is the CLI lookup for this page — handy in READMEs and docs.