afk-issue

star 0

Implement ONE GitHub issue end-to-end with the afk-task-runner, then the code-reviewer, opening a PR (default base main, override with a branch). Orchestration glue for a single targeted issue — use when the user says "afk issue

danievanzyl By danievanzyl schedule Updated 6/3/2026

name: afk-issue description: Implement ONE GitHub issue end-to-end with the afk-task-runner, then the code-reviewer, opening a PR (default base main, override with a branch). Orchestration glue for a single targeted issue — use when the user says "afk issue #N", "implement #N and review it", "run the afk runner on issue N", "build and review issue N", or wants one locked-design issue built + reviewed as a PR. For MULTIPLE issues into an integration branch, use feature-branch-fan-in instead. argument-hint: [base-branch]

afk-issue

Single-issue sibling of feature-branch-fan-in: one targeted issue → afk-task-runnercode-reviewer → a reviewed PR. Orchestration glue, not a reimplementation — it chains agents/skills you already have and relies on the existing hooks. Do not re-grill the design or re-write the issue here (upstream: grill-with-docs, to-issues).

$ARGUMENTS = <issue-number> [base-branch]. Base defaults to main.

Why a skill at all (vs just spawning the runner)

afk-task-runner is written to select the next queue task, not to take a target. Left to its defaults it may pick a different issue and defaults its PR toward main. This skill (a) pins it to issue #N, (b) sets the PR base correctly, (c) sequences the reviewer against the runner's worktree, and (d) cleans up — leaning on the hooks rather than duplicating them.

What the hooks already do (don't re-implement)

  • On afk-task-runner stop → afk-handoff.sh writes .claude/state/issue-N.json (branch, worktree, pr, last_sha) and posts a PR comment.
  • code-reviewer reads that state file and cds into the runner's worktree to review (it does NOT gh pr checkout).
  • On code-reviewer stop → code-reviewer-push.sh pushes the RALPH: Review - commits so the PR updates.

Parameters — resolve first, never hardcode

Param Source
issue number $ARGUMENTS (first token)
base branch $ARGUMENTS (second token); default main
owner/repo gh repo view --json nameWithOwner -q .nameWithOwner
gh account memory or CLAUDE.md (account routing per org); ask if unknown
child branch <type>/<N>-<slug> from the issue title (must match the branch-name hook: feat|fix|chore|refactor|perf|docs|test/<N>-…)

Preconditions

  • Issue #N exists and its design is locked (a "design locked" comment, plus CONTEXT.md / relevant ADR on the base branch). If not locked → stop, point at grill-with-docs.
  • If base ≠ main, that branch is pushed to origin (a PR can't target a base that isn't on origin).
  • Correct gh account active for the org: gh auth switch -u <account>.

Pipeline

  1. Spawn afk-task-runner (worktree isolation) with the targeted prompt below. It implements issue #N via TDD, runs the feedback loop, commits, and opens the PR. Its stop fires afk-handoff.shissue-N.json.
  2. Verify the PR points the right way: gh pr view <n> --json baseRefName,headRefName → base = <base>, head = <child-branch>.
  3. Spawn code-reviewer with issue #N + title (template below). It reads issue-N.json, cds into the runner's worktree, reviews against locked intent + correctness, fixes, and commits RALPH: Review -. Its stop fires code-reviewer-push.sh → PR updates.
  4. Report: PR URL, reviewer verdict (APPROVE / CHANGES MADE / BLOCKED-needs-human), final test result.
  5. Clean up the worktree (AFTER review, not before — the reviewer reused it): git worktree remove --force <worktree-from-issue-N.json> then git worktree prune.

Default: leave the PR open for a human merge (the PR-to-main is the review gate). Merge only on explicit request: gh pr merge <n> --squash --delete-branch.

Closes vs Addresses (base-dependent)

  • base = main → PR body Closes #N (GitHub auto-closes the issue on merge to the default branch).
  • base = a non-default branch → PR body Addresses #N (it will NOT auto-close until that branch reaches main). Say so in the report.

afk-task-runner prompt template

Implement GitHub issue #N ONLY ("") in <owner>/<repo>. Work on issue #N ONLY — do NOT select a different issue from the queue, do NOT touch other issues' scope. Use gh account <code><account></code> — run <code>gh auth switch -u <account></code> first.</p> <p>The design is ALREADY LOCKED — do not re-design or re-grill. Read first: (1) <code>gh issue view N --repo <owner>/<repo> --comments</code> → the "design locked" comment is authoritative; (2) <code>CONTEXT.md</code> → <relevant entry>; (3) <code>docs/adr/<NNNN>.md</code>.</p> <Paste the locked design summary here.> <p>TDD. Feedback loop must pass before the PR (use <code>.claude/state/feedback-cmds.json</code> if present, else infer: go → <code>go vet ./... && go test -race ./...</code>; node → the project's test + typecheck; etc.).</p> <p>Branch + PR: your isolated worktree is branched from <code><base></code>. Work on child branch <code><child-branch></code> (format <code><type>/N-<slug></code>). Open the PR with <strong>base = <code><base></code></strong> and head = <code><child-branch></code>. PR body: "<Closes|Addresses> #N" (per the base). Do NOT close or modify the issue. Report the PR URL, your worktree path, and the exact test result.</p> </blockquote> <h2>code-reviewer prompt template</h2> <blockquote> <p>Review the work for GitHub issue #N — "<title>" — in <owner>/<repo>. <code>gh auth switch -u <account></code> first. Locate the branch/worktree via <code>.claude/state/issue-N.json</code> (the <code>branch</code> + <code>worktree</code> fields) and <code>cd</code> there — do NOT <code>gh pr checkout</code>.</p> <p>Review against the LOCKED intent AND correctness: read the issue's "design locked" comment, <code>CONTEXT.md</code> <entry>, and the ADR. <List the high-value, design-specific checks most likely to be subtly wrong.></p> <p>Fix issues + write missing tests. Commit to the branch with messages prefixed <code>RALPH: Review - </code> (the push hook ships them). Feedback loop must pass after fixes. Return severity-tagged findings, commit SHAs, final test result, and a verdict (APPROVE / CHANGES MADE / BLOCKED-needs-human).</p> </blockquote> <h2>When NOT to use this skill</h2> <ul> <li><strong>Multiple issues</strong> → <code>feature-branch-fan-in</code> (integration branch + consolidated PR).</li> <li><strong>Design not locked</strong> → <code>grill-with-docs</code> first.</li> <li><strong>No issue yet</strong> → <code>to-issues</code> first.</li> </ul> </article> </div> <!-- Right: Metadata & Command Sidebar --> <div class="w-full lg:w-80 shrink-0 flex flex-col gap-6" data-astro-cid-7zzsworf> <!-- Install Card --> <div class="p-6 rounded-xl bg-surface-container border border-border/80 flex flex-col gap-4 shadow-sm" data-astro-cid-7zzsworf> <span class="text-xs font-bold uppercase tracking-widest text-on-surface-variant/60 font-mono" data-astro-cid-7zzsworf>Install via CLI</span> <div class="flex flex-col gap-2" data-astro-cid-7zzsworf> <div id="detail-install-cmd" class="font-mono text-[11px] p-3 rounded-lg bg-black/40 border border-border select-all break-all text-primary font-bold leading-relaxed" data-astro-cid-7zzsworf> npx skills add https://github.com/danievanzyl/code-skills --skill afk-issue </div> <button id="detail-copy-btn" class="w-full py-2.5 rounded-lg bg-primary hover:bg-primary-hover text-on-primary font-sans font-bold text-sm shadow transition-all active:scale-95 flex items-center justify-center gap-1.5" data-astro-cid-7zzsworf> <span class="material-symbols-outlined text-[16px]" data-astro-cid-7zzsworf>content_copy</span> <span data-astro-cid-7zzsworf>Copy Command</span> </button> </div> </div> <!-- Details & Stats Card --> <div class="p-6 rounded-xl bg-surface-container border border-border/80 flex flex-col gap-4 shadow-sm text-on-surface" data-astro-cid-7zzsworf> <span class="text-xs font-bold uppercase tracking-widest text-on-surface-variant/60 font-sans" data-astro-cid-7zzsworf>Repository Details</span> <div class="flex flex-col gap-3.5" data-astro-cid-7zzsworf> <div class="flex justify-between items-center text-sm" data-astro-cid-7zzsworf> <span class="text-on-surface-variant/70 flex items-center gap-1.5" data-astro-cid-7zzsworf> <span class="material-symbols-outlined text-[16px] text-on-surface-variant/60" data-astro-cid-7zzsworf>star</span> Stars </span> <span class="font-mono font-bold text-on-surface" data-astro-cid-7zzsworf>0</span> </div> <div class="flex justify-between items-center text-sm" data-astro-cid-7zzsworf> <span class="text-on-surface-variant/70 flex items-center gap-1.5" data-astro-cid-7zzsworf> <span class="material-symbols-outlined text-[16px] text-on-surface-variant/60" data-astro-cid-7zzsworf>call_split</span> Forks </span> <span class="font-mono font-bold text-on-surface" data-astro-cid-7zzsworf>0</span> </div> <div class="flex justify-between items-center text-sm" data-astro-cid-7zzsworf> <span class="text-on-surface-variant/70 flex items-center gap-1.5" data-astro-cid-7zzsworf> <span class="material-symbols-outlined text-[16px] text-on-surface-variant/60" data-astro-cid-7zzsworf>navigation</span> Branch </span> <span class="font-mono bg-surface border border-border px-2 py-0.5 rounded text-[11px] text-on-surface-variant" data-astro-cid-7zzsworf>main</span> </div> <div class="flex justify-between items-start text-sm" data-astro-cid-7zzsworf> <span class="text-on-surface-variant/70 flex items-center gap-1.5 mt-0.5" data-astro-cid-7zzsworf> <span class="material-symbols-outlined text-[16px] text-on-surface-variant/60" data-astro-cid-7zzsworf>article</span> Path </span> <span class="font-mono bg-surface border border-border px-2 py-0.5 rounded text-[11px] text-on-surface-variant truncate max-w-[150px]" title="SKILL.md" data-astro-cid-7zzsworf>SKILL.md</span> </div> </div> </div> <!-- Occupations Tag Card --> <!-- Related Creators Card --> <div class="p-6 rounded-xl bg-surface-container border border-border/80 flex flex-col gap-3 shadow-sm" data-astro-cid-7zzsworf> <span class="text-xs font-bold uppercase tracking-widest text-on-surface-variant/60 font-sans" data-astro-cid-7zzsworf>More from Creator</span> <div class="flex items-center gap-2" data-astro-cid-7zzsworf> <img class="w-8 h-8 rounded-full border border-border" src="https://avatars.githubusercontent.com/u/2434731?v=4" alt="danievanzyl" onerror="this.src='https://avatars.githubusercontent.com/u/9919?v=4'" data-astro-cid-7zzsworf> <div class="flex flex-col min-w-0" data-astro-cid-7zzsworf> <span class="font-bold text-sm truncate text-on-surface" data-astro-cid-7zzsworf>danievanzyl</span> <a href="/?creator=danievanzyl" class="text-xs text-primary hover:underline font-semibold transition-all" data-astro-cid-7zzsworf>Explore all skills →</a> </div> </div> </div> </div> </div> </div> </div> <script> const copyBtn = document.getElementById("detail-copy-btn"); const installCmd = document.getElementById("detail-install-cmd"); if (copyBtn && installCmd) { copyBtn.addEventListener("click", () => { const cmd = installCmd.textContent.trim(); navigator.clipboard.writeText(cmd).then(() => { const originalText = copyBtn.innerHTML; copyBtn.innerHTML = ` <span class="material-symbols-outlined text-[16px]">check</span> <span>Copied!</span> `; copyBtn.style.background = "#10b981"; copyBtn.style.borderColor = "#10b981"; setTimeout(() => { copyBtn.innerHTML = originalText; copyBtn.style.background = ""; copyBtn.style.borderColor = ""; }, 1500); }); }); } </script> </div> <!-- Footer --> <footer class="border-t border-border bg-surface-container-low text-on-surface-variant py-8 px-gutter mt-16 rounded-xl"> <div class="max-w-container-max mx-auto flex flex-col md:flex-row justify-between items-center gap-6"> <div class="flex items-center gap-2"> <div class="w-6 h-6 rounded bg-primary bg-opacity-20 flex items-center justify-center"> <span class="material-symbols-outlined text-primary text-sm">code_blocks</span> </div> <span class="font-bold text-on-surface text-sm">SkillMD</span> </div> <div class="flex flex-wrap justify-center gap-6 text-sm"> <a href="/about" class="hover:text-primary transition-colors">About Us</a> <a href="/contact" class="hover:text-primary transition-colors">Contact Us</a> <a href="/privacy" class="hover:text-primary transition-colors">Privacy Policy</a> <a href="/terms" class="hover:text-primary transition-colors">Terms of Service</a> <a href="/support" class="hover:text-primary transition-colors">Support</a> </div> <div class="text-xs text-on-surface-variant/80"> © 2026 SkillMD. All rights reserved. </div> </div> </footer> </main> <!-- Script for Theme Toggle, Mobile Menu, and Sidebar Filter Redirection --> <script> // Theme setup const savedTheme = localStorage.getItem("theme") || "dark"; function applyTheme(theme) { document.documentElement.classList.remove("dark", "green", "dracula", "nord"); if (theme === "dark") { document.documentElement.classList.add("dark"); } else if (theme === "green") { document.documentElement.classList.add("dark", "green"); } else if (theme === "dracula") { document.documentElement.classList.add("dark", "dracula"); } else if (theme === "nord") { document.documentElement.classList.add("dark", "nord"); } document.documentElement.setAttribute("data-theme", theme); const themeMoon = document.getElementById("theme-moon"); const themeSun = document.getElementById("theme-sun"); const themeLeaf = document.getElementById("theme-leaf"); const themeDracula = document.getElementById("theme-dracula"); const themeNord = document.getElementById("theme-nord"); if (themeMoon && themeSun && themeLeaf && themeDracula && themeNord) { themeMoon.style.display = theme === "dark" ? "inline" : "none"; themeSun.style.display = theme === "light" ? "inline" : "none"; themeLeaf.style.display = theme === "green" ? "inline" : "none"; themeDracula.style.display = theme === "dracula" ? "inline" : "none"; themeNord.style.display = theme === "nord" ? "inline" : "none"; } } applyTheme(savedTheme); const themeToggleBtn = document.getElementById("theme-toggle-btn"); if (themeToggleBtn) { themeToggleBtn.addEventListener("click", () => { const currentTheme = document.documentElement.getAttribute("data-theme") || "dark"; let newTheme = "dark"; if (currentTheme === "dark") { newTheme = "light"; } else if (currentTheme === "light") { newTheme = "green"; } else if (currentTheme === "green") { newTheme = "dracula"; } else if (currentTheme === "dracula") { newTheme = "nord"; } else { newTheme = "dark"; } applyTheme(newTheme); localStorage.setItem("theme", newTheme); }); } // Mobile menu toggle and sidebar logic const mobileMenuToggle = document.getElementById("mobile-menu-toggle"); const sidebarMenu = document.getElementById("sidebar-menu"); const sidebarOverlay = document.getElementById("sidebar-overlay"); function isMobile() { return window.innerWidth < 768; // 768px is the 'md' breakpoint in Tailwind } function openSidebar() { if (sidebarMenu) { sidebarMenu.classList.remove("-translate-x-full"); } if (sidebarOverlay) { sidebarOverlay.classList.remove("hidden"); } } function closeSidebar() { if (sidebarMenu && isMobile()) { sidebarMenu.classList.add("-translate-x-full"); } if (sidebarOverlay) { sidebarOverlay.classList.add("hidden"); } } if (mobileMenuToggle && sidebarMenu) { mobileMenuToggle.addEventListener("click", (e) => { e.stopPropagation(); if (isMobile()) { const isClosed = sidebarMenu.classList.contains("-translate-x-full"); if (isClosed) { openSidebar(); } else { closeSidebar(); } } }); document.addEventListener("click", (e) => { if (isMobile()) { if (!sidebarMenu.contains(e.target) && !mobileMenuToggle.contains(e.target)) { closeSidebar(); } } }); if (sidebarOverlay) { sidebarOverlay.addEventListener("click", () => { if (isMobile()) { closeSidebar(); } }); } // Collapse sidebar when clicking a filter button, creator button, or nav item inside it sidebarMenu.addEventListener("click", (e) => { if (isMobile()) { const clickTarget = e.target.closest("button, a"); if (clickTarget) { closeSidebar(); } } }); // Sync sidebar state on window resize window.addEventListener("resize", () => { if (!isMobile()) { // Desktop: sidebar should be visible, no overlay if (sidebarMenu) { sidebarMenu.classList.remove("-translate-x-full"); } if (sidebarOverlay) { sidebarOverlay.classList.add("hidden"); } } else { // Mobile: start collapsed if (sidebarMenu) { sidebarMenu.classList.add("-translate-x-full"); } if (sidebarOverlay) { sidebarOverlay.classList.add("hidden"); } } }); } // If not on homepage, redirect on sidebar filter click const isHomepage = window.location.pathname === "/"; document.querySelectorAll("#occupation-filters .filter-btn").forEach(btn => { btn.addEventListener("click", (e) => { const occ = e.currentTarget.getAttribute("data-occupation"); if (!isHomepage) { window.location.href = occ ? `/?occupation=${encodeURIComponent(occ)}` : "/"; } }); }); document.querySelectorAll("#creator-filters .creator-btn").forEach(btn => { btn.addEventListener("click", (e) => { const creator = e.currentTarget.getAttribute("data-creator"); if (!isHomepage) { window.location.href = `/?creator=${encodeURIComponent(creator)}`; } }); }); </script> </body> </html>