Gh Apply

Find an issue in the 'apply' stage, read its implementation plan, implement all code changes, create a pull request, and move the…

goodtribes-org updated 2mo ago
Claude CodeGeneric
View source ↗
# GitHub Apply Worker

Find an issue in the 'apply' stage, read its implementation plan, implement all code changes, create a pull request, and move the card to 'test'. Runs continuously — polls every 5 minutes when the queue is empty.

## Usage

/gh-apply


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 'apply' after a human moves the card from 'review → apply', signifying the implementation plan has been approved. This skill implements all code changes from the plan and opens a pull request on the goodtribes-org org repository.

## Workflow

Steps 0 and 0.5 run **once** at startup. Steps 1–15 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.


0.5. Verify local repo setup (runs once at startup)

Check that all three sub-project repositories are cloned locally and have the correct git remotes. Run these checks for each sub-project in this order:

Sub-project Directory Remote Expected URL
kickfix kickfix/ goodtribes git@github.com:goodtribes-org/kickfix.git
asylguiden.se asylguiden.se/ goodtribes git@github.com:goodtribes-org/asylguiden.se.git
goodtribes.org goodtribes.org/ origin git@github.com:goodtribes-org/goodtribes.org.git

Check A — Directory exists:

ls /home/mattias/projects/goodtribes.org/<subdir>/

If the directory is missing, clone it automatically (no confirmation needed — cloning is always safe):

git clone git@github.com:goodtribes-org/<repoName>.git /home/mattias/projects/goodtribes.org/<subdir>

For kickfix and asylguiden.se only, rename the default origin remote to goodtribes:

git -C /home/mattias/projects/goodtribes.org/<subdir> remote rename origin goodtribes

For goodtribes.org, keep origin as-is.

If git clone fails, pause and ask the user via AskUserQuestion:

Sub-project setup problem: <name>
Issue: clone failed

Error: <full error output>

Options:
  A) Retry the clone (fix SSH/network first, then select A)
  B) Skip this sub-project for this session (issues labelled '<name>' will be rejected at step 5)
  C) Stop the worker entirely

Wait for the user's response. If A: retry the clone. If B: mark sub-project as unavailable in session memory and continue to the next sub-project. If C: stop entirely.

Check B — Is a git repo:

git -C /home/mattias/projects/goodtribes.org/<subdir> rev-parse --git-dir 2>&1

If this fails (directory exists but is not a git repository), ask the user via AskUserQuestion — do not auto-fix:

Sub-project setup problem: <name>
Issue: directory exists at <subdir> but is not a git repository

Error: <command output>

Options:
  A) Skip this sub-project for this session
  B) Stop the worker entirely

Check C — Remote name and URL correct:

git -C /home/mattias/projects/goodtribes.org/<subdir> remote get-url <remoteName> 2>&1

If the remote doesn't exist or points to the wrong URL, ask the user via AskUserQuestion and offer to fix:

Sub-project setup problem: <name>
Issue: <remote '<remoteName>' not found | remote '<remoteName>' points to '<actualUrl>' instead of '<expectedUrl>'>

Options:
  A) Fix automatically (run: git remote <add|set-url> <remoteName> <expectedUrl>)
  B) Skip this sub-project for this session
  C) Stop the worker entirely

If A: run the appropriate fix command, then re-run Check C. If it still fails, ask again with the new error output.

Fix commands:

  • Remote missing: git -C <subdir> remote add <remoteName> <expectedUrl>
  • Remote wrong URL: git -C <subdir> remote set-url <remoteName> <expectedUrl>

After all checks pass for all three sub-projects, report:

Pre-flight OK: kickfix ✓  asylguiden.se ✓  goodtribes.org ✓

Then proceed to the loop.


↻ LOOP — repeat from here after each issue or after sleeping

1. List items in 'apply' 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 apply (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 — the repo the issue lives in (e.g. goodtribes-org/kickfix)
  • projectNumber and projectNodeId — the board this item came from (needed for step 13)

If no items in 'apply' status on any board, OR all candidates have a picked-by-* label:

echo "No issues in apply — 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 # with label $PICKED_LABEL."

Store $PICKED_LABEL — yo ```

Maintain Gh Apply?

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 Apply on getagentictools](https://getagentictools.com/loops/goodtribes-org-github-apply-worker?ref=badge)
npx agentictools info loops/goodtribes-org-github-apply-worker

The second line is the CLI lookup for this page — handy in READMEs and docs.