-
Notifications
You must be signed in to change notification settings - Fork 0
Add issue-runner skill — autonomous sprint orchestrator #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
85fda1b
Add issue-runner skill — autonomous sprint orchestrator with board ma…
kirich1409 b072460
Fix label name, agent refs, and quality loop commands per review
kirich1409 e355881
Update board reading to use project fields instead of labels
kirich1409 76d887f
Use REST issue_dependencies_summary for dependency checks
kirich1409 399f263
Address Copilot re-review: remove disable-model-invocation, clarify p…
kirich1409 31c81bd
Fix label fetch, blocked exclusion, and card timing in Phase 3
kirich1409 0c53017
Fix pagination, worktree mkdir, bash permissions, and org label
kirich1409 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,301 @@ | ||
| --- | ||
| name: issue-runner | ||
| description: > | ||
| Explicit-only skill — invoke only via /issue-runner. | ||
| Autonomous GitHub Issue sprint runner: reads the project board (androidbroadcast/Relay, | ||
| project #2), assigns tasks to subagents, moves cards through statuses | ||
| (Todo → In Progress → Review → Done), and drives each issue through the full | ||
| dev-workflow pipeline (plan → implement → quality → PR). | ||
| --- | ||
|
|
||
| # Issue Runner — Relay Project | ||
|
|
||
| Project manager + orchestrator: reads the board → assigns issues to agents → | ||
| moves cards by status → each agent implements, quality loop, PR → board reflects reality. | ||
|
|
||
| --- | ||
|
|
||
| ## Board constants | ||
|
|
||
| ``` | ||
| Project: org androidbroadcast, project #2 (org-level ProjectV2, not repo-scoped) | ||
| Project ID: PVT_kwDOA59kY84BUaDa | ||
| Status field: PVTSSF_lADOA59kY84BUaDazhBiYJE | ||
| Todo: f75ad846 | ||
| In Progress: 47fc9ee4 | ||
| Review: 1be2fb87 | ||
| Done: 98236657 | ||
| Complexity: PVTSSF_lADOA59kY84BUaDazhBm5vc | ||
| S: 58b3409e | ||
| M: 8da00f47 | ||
| L: 581040d4 | ||
| Wave: PVTIF_lADOA59kY84BUaDazhBm6NQ (IterationField — value is iteration title) | ||
| ``` | ||
|
kirich1409 marked this conversation as resolved.
|
||
|
|
||
| > These IDs are stable for the lifetime of the project fields. If a field/option is deleted and recreated, re-query with: | ||
| > `gh api graphql -f query='{ organization(login:"androidbroadcast") { projectV2(number:2) { fields(first:30) { nodes { ... on ProjectV2SingleSelectField { id name options { id name } } ... on ProjectV2IterationField { id name } } } } } }'` | ||
|
|
||
| ### Move a card to a status | ||
|
|
||
| ```bash | ||
| gh api graphql -f query='mutation { | ||
| updateProjectV2ItemFieldValue(input: { | ||
| projectId: "PVT_kwDOA59kY84BUaDa" | ||
| itemId: "<ITEM_ID>" | ||
| fieldId: "PVTSSF_lADOA59kY84BUaDazhBiYJE" | ||
| value: { singleSelectOptionId: "<STATUS_OPTION_ID>" } | ||
| }) { projectV2Item { id } } | ||
| }' | ||
| ``` | ||
|
|
||
| ### Get all board items with issue numbers and statuses | ||
|
|
||
| ```bash | ||
| gh api graphql -f query=' | ||
| { | ||
| organization(login: "androidbroadcast") { | ||
| projectV2(number: 2) { | ||
| items(first: 100, after: $cursor) { | ||
| pageInfo { hasNextPage endCursor } | ||
| nodes { | ||
| id | ||
|
kirich1409 marked this conversation as resolved.
|
||
| content { | ||
| ... on Issue { | ||
| number title | ||
| issueType { name } | ||
| parent { number title } | ||
| labels(first: 10) { nodes { name } } | ||
| } | ||
| } | ||
| fieldValues(first: 20) { | ||
| nodes { | ||
| ... on ProjectV2ItemFieldSingleSelectValue { | ||
| name | ||
| field { ... on ProjectV2SingleSelectField { name } } | ||
| } | ||
| ... on ProjectV2ItemFieldIterationValue { | ||
| title | ||
| field { ... on ProjectV2IterationField { name } } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }' | ||
| ``` | ||
|
|
||
| Paginate: repeat with `-f cursor="<endCursor>"` while `pageInfo.hasNextPage == true`. Collect all nodes across pages. | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 0: Setup | ||
|
|
||
| ```bash | ||
| gh auth status | ||
| git worktree list | ||
| mkdir -p .worktree | ||
| grep -q "swarm-report" .gitignore || echo "swarm-report/" >> .gitignore | ||
| ``` | ||
|
kirich1409 marked this conversation as resolved.
|
||
|
|
||
| --- | ||
|
|
||
| ## Phase 1: Read the board | ||
|
|
||
| Fetch all board items (query above). For each item: | ||
| - Extract issue number, title, current Status, Complexity field, Wave field, parent epic | ||
| - Skip items with `issueType.name == "Feature"` — those are Epics, not Tasks | ||
| - Ignore items already in **Done** | ||
| - Collect item IDs — you need them to move cards | ||
|
|
||
| Build a priority-ordered queue: | ||
| - Group by Wave iteration title: "Wave 1" first, then "Wave 2"…"Wave 5", no wave last | ||
| - Within wave: Complexity `S` → `M` → `L` | ||
| - Items labeled `blocker` → log as pre-blocked, skip | ||
|
|
||
|
kirich1409 marked this conversation as resolved.
|
||
| **Dependency check:** use the REST field `issue_dependencies_summary.blocked_by`: | ||
| ```bash | ||
| gh api repos/androidbroadcast/Relay/issues/<NUMBER> \ | ||
| --jq '.issue_dependencies_summary.blocked_by' | ||
| ``` | ||
| If `blocked_by > 0` → the issue has unresolved blockers → mark BLOCKED. No body parsing needed — GitHub Relations are the authoritative source. | ||
|
|
||
|
kirich1409 marked this conversation as resolved.
|
||
| --- | ||
|
|
||
| ## Phase 2: State file | ||
|
|
||
| Save to `swarm-report/issue-runner-state.md`. Re-read at the start of every turn. | ||
|
|
||
| ```markdown | ||
| # Issue Runner State | ||
| Started: <ISO timestamp> | ||
|
|
||
| ## Queue | ||
| ### Wave 1 | ||
| - [ ] #N <title> [item_id: PVTI_xxx, complexity:S] | ||
| ### Wave 2 | ||
| - [ ] #N <title> [item_id: PVTI_xxx, complexity:M] | ||
|
|
||
| ## In Progress | ||
| - #N <title> (item_id: PVTI_xxx) — agent running | ||
|
|
||
| ## Completed | ||
| | Issue | Item ID | PR | Result | | ||
| |-------|---------|----|--------| | ||
|
|
||
| ## Blocked / Failed | ||
| | Issue | Reason | | ||
| |-------|--------| | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 3: Wave loop | ||
|
|
||
| **Do not start wave N+1 until all wave N agents are done.** | ||
|
|
||
| For each wave: | ||
| 1. Separate wave items into **ready** (not BLOCKED) and **skipped** (BLOCKED) | ||
| 2. Print: "Wave N: M ready, K skipped (blocked)" | ||
| 3. Move only **ready** items to **In Progress** on the board | ||
| 4. Launch all ready agents simultaneously (one Agent call per issue, all in one message) | ||
| 5. As each agent starts successfully, confirm the card stays **In Progress**; if an agent fails to start, revert its card to **Todo** | ||
| 6. As agents complete, update board and state file | ||
| 7. Print wave summary (N done / N blocked / N failed) | ||
| 8. Pause — user can stop or redirect before the next wave | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 4: Per-issue agent prompt | ||
|
|
||
| ``` | ||
| ## Task | ||
| GitHub Issue #<NUMBER>: <TITLE> | ||
| Epic: <PARENT_EPIC_TITLE or "none"> | ||
| Complexity: <S|M|L> | ||
| Wave: <Wave N> | ||
| Board item ID: <PVTI_xxx> | ||
|
|
||
| <FULL ISSUE BODY> | ||
|
|
||
| --- | ||
|
|
||
| Your job: implement this issue end-to-end and create a PR. | ||
|
|
||
| ## Step 1 — Read the spec | ||
|
|
||
| docs/architecture/relay-cloud-decomposition.md | ||
| → find the section for this task (e.g. T-3, T-7a) by matching task ID in the title | ||
| → read full description and acceptance criteria — this is your definition of done | ||
|
|
||
| docs/architecture/relay-cloud-architecture.md (context) | ||
| docs/testplans/relay-cloud-mvp-test-plan.md (if relevant) | ||
|
|
||
| ## Step 2 — Worktree | ||
|
|
||
|
kirich1409 marked this conversation as resolved.
|
||
| git worktree add .worktree/<SLUG> -b feature/<SLUG> | ||
|
|
||
| SLUG = kebab-case from issue title. All work happens in this worktree. | ||
|
|
||
| ## Step 3 — Pipeline (by Complexity field) | ||
|
|
||
| S → implement → quality loop → PR | ||
| M → plan (swarm-report/<N>-<SLUG>-plan.md) → implement → quality loop → PR | ||
| L → research → plan → implement → quality loop → PR | ||
|
|
||
| Backend (Rust): use `rust-backend-engineer` agent (defined in `.claude/agents/`). | ||
| Frontend (Swift/TCA): use `developer-workflow:swiftui-developer` plugin agent. | ||
|
|
||
| > `developer-workflow:*` agents are part of the globally installed `krozov-ai-tools/developer-workflow` plugin — available in all sessions, not defined per-project. | ||
|
|
||
| ## Step 4 — Quality loop (max 3 attempts per gate) | ||
|
|
||
| 1. Build: cd runner && cargo build (backend) | ||
| xcodebuild build -project MacApp/Relay.xcodeproj -scheme Relay -destination 'platform=macOS,arch=arm64' CODE_SIGNING_ALLOWED=NO (frontend) | ||
| 2. Format: cd runner && cargo fmt --check (backend) | ||
| 3. Lint: cd runner && cargo clippy -- -D warnings (backend) | ||
| cd MacApp && swiftlint lint --strict (frontend) | ||
| 4. Tests: cd runner && cargo test (backend) | ||
| xcodebuild test -project MacApp/Relay.xcodeproj -scheme Relay -destination 'platform=macOS,arch=arm64' CODE_SIGNING_ALLOWED=NO (frontend) | ||
| 5. Review: `developer-workflow:code-reviewer` plugin agent with task description + git diff | ||
|
kirich1409 marked this conversation as resolved.
kirich1409 marked this conversation as resolved.
kirich1409 marked this conversation as resolved.
|
||
|
|
||
| ## Step 5 — PR | ||
|
|
||
| gh pr create --repo androidbroadcast/Relay \ | ||
| --title "<ISSUE TITLE>" \ | ||
| --body "Summary + acceptance criteria checklist (all checked) + Closes #<NUMBER>" | ||
|
|
||
| "Closes #<NUMBER>" in the body closes the issue automatically on merge. | ||
|
|
||
| ## Step 6 — Report back (exactly this format) | ||
|
|
||
| STATUS: DONE|BLOCKED|FAILED | ||
| PR: <url or none> | ||
| ISSUE: #<NUMBER> | ||
| ITEM_ID: <PVTI_xxx> | ||
| NOTES: <one-line summary or blocker reason> | ||
|
|
||
| ## Constraints | ||
| - Never commit to main | ||
| - Worktree: .worktree/<SLUG>, branch: feature/<SLUG> | ||
| - Reports: swarm-report/<N>-<SLUG>-*.md | ||
| - Max 3 attempts per quality gate; escalate as FAILED if still broken | ||
| - If a required dependency is not merged: BLOCKED "depends on #N (open)" | ||
| ``` | ||
|
|
||
| **Model by Complexity field:** | ||
| - `L` → `model: opus` | ||
| - `M` → default (sonnet) | ||
| - `S` → `model: haiku` | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 5: Board updates after agent completes | ||
|
|
||
| | Agent result | Board action | State file | | ||
| |---|---|---| | ||
| | DONE | Move to **Review** | → Completed | | ||
| | BLOCKED | Move to **Todo** | → Blocked/Failed | | ||
| | FAILED | Move to **Todo** | → Blocked/Failed | | ||
| | PR merged (poll or webhook) | Move to **Done** | → mark closed | | ||
|
|
||
| ### Check if PR is merged (after wave) | ||
|
|
||
| ```bash | ||
| gh pr view <PR_NUMBER> --repo androidbroadcast/Relay --json state,mergedAt | ||
| ``` | ||
|
|
||
| If merged → move board item to Done. | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 6: Dependency retry | ||
|
|
||
| After each wave, re-check BLOCKED issues: | ||
| - If the blocking issue is now Done on the board → add dependent to next wave queue | ||
| - Still open → keep BLOCKED | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 7: Final report | ||
|
|
||
| ``` | ||
| # Issue Runner — Final Report | ||
| Date: <date> | ||
|
|
||
| ✅ Completed: N (#N → PR url, ...) | ||
| ⚠️ Blocked: N (reasons) | ||
| ❌ Failed: N (details) | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Error handling | ||
|
|
||
| | Situation | Action | | ||
| |---|---| | ||
| | BLOCKED | Move card to Todo, log, continue | | ||
| | FAILED | Move card to Todo, log, continue | | ||
| | Build fails 3+ times | Escalate to user with error | | ||
| | No Todo/In-Progress items | Print "Nothing to do" and exit | | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.