From red-skills
Autonomous loop that drains the `ready-for-agent` queue on the issue tracker. Each iteration claims an issue, runs it in an isolated worktree, executes with claude or codex, merges back to main, and closes the issue. Use when the user wants to run AFK execution, drain a PRD, hammer specific issues, or otherwise let agents grind through the backlog.
How this skill is triggered — by the user, by Claude, or both
Slash command
/red-skills:afk [--prd N | --issues N,N,N] [--runner claude|codex] [-n N] [--once][--prd N | --issues N,N,N] [--runner claude|codex] [-n N] [--once]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Drain the agent-ready backlog. Single skill that owns issue selection, worktree isolation, inner-agent execution, GitHub state coordination, merge-back, and runner-fallback.
Drain the agent-ready backlog. Single skill that owns issue selection, worktree isolation, inner-agent execution, GitHub state coordination, merge-back, and runner-fallback.
/afk — every issue currently labelled ready-for-agent./afk --prd 42 — only issues that reference PRD #42 (by prd: #42 line in body, parent link, or prd:42 label)./afk --issues 356,359,362 — explicit list, in that order./afk --runner codex — pin a backend instead of alternating on exhaustion./afk -n 5 — cap at five issues (default: drain until empty)./afk --once — single supervised iteration. Same as scripts/once.sh. Use for debugging the prompt./afk monitor — readonly status board, reads .red/tmp/afk-state.json from another terminal.Refuse to start if any of these fail. The user fixes them, you don't.
git remote -v shows only SSH remotes. Reject HTTPS — never auto-rewrite.gh auth status succeeds.main branch and git -C primary log -1 main works.ready-for-agent exists. If not, point at /triage.pnpm is on PATH (logger and tooling guidelines assume pnpm).Run before the first iteration:
.red/tmp/ exists. Create it..red/tmp/ is in .gitignore of the primary checkout. Append if missing..red/tmp/afk-state.json with the schema in state-schema.md. Atomic write.--runner flag > env AFK_RUNNER > claude. Load runner-claude.md or runner-codex.md so the spawn command is ready.SAFETY.md. It is binding for every shell action the loop takes.Before issue selection, /afk counts open issues in states it cannot consume:
unlabeled — never triagedneeds-triage — triage in progressneeds-info — waiting on reporterIf any of those are non-zero, print a warning and (on a TTY, not in --once) prompt to confirm before proceeding. This catches the "issue perdida" case where a fresh report never made it through /triage and is silently invisible to /afk.
The systemic fix is the red-issues-needs-triage.yml workflow installed by /setup-red-skills, which auto-applies needs-triage to every fresh issue. The straggler check is the in-loop safety net for repos where the workflow isn't installed yet.
Pull the candidate list with gh issue list --label ready-for-agent --state open --json number,title,labels,body --limit 100.
Apply filters in this order:
--issues was passed: keep only those numbers, in argument order. Error if any are missing or not labelled ready-for-agent.--prd was passed: keep issues with prd: #N in the body, a parent link to issue N, or a prd:N label.ready-for-agent issues. Sort by triage priority — priority:high before priority:low (and unlabelled), then by issue number ascending.If the list is empty, print <promise>NO MORE TASKS</promise> and exit 0.
/afk slice)Canonical state machine lives in setup-red-skills/triage-labels.md. The portion /afk touches:
ready-for-agent
│
(1) claim
remove ready-for-agent
add running
post start comment
│
▼
running
┌───┴───┐
│ │ heartbeat sub-shell posts :one: → :four: every 10 min
│ │
│ │ inner agent works in worktree → emits DONE | BLOCKED
│ │ orchestrator runs feedback loops, then merges to main
│ │
│ ├──── DONE + green + merged + pushed
│ │ │
│ │ (4a) close
│ │ remove running
│ │ gh issue close --reason completed
│ │ │
│ │ ▼
│ │ closed
│ │
│ └──── BLOCKED, or merge conflict, or both runners exhausted
│ │
│ (4b) release
│ remove running
│ add ready-for-human
│ post blocker comment with worktree path
│ │
│ ▼
│ ready-for-human (worktree preserved at moment of blocker)
│
└──── orchestrator interrupted (SIGINT/SIGTERM)
│
(4c) release
remove running
restore ready-for-agent
post interruption comment
│
▼
ready-for-agent (next /afk run can pick it up)
Label transitions are atomic via gh issue edit --remove-label A --add-label B. Two parallel /afk runners cannot both claim the same issue because the second attempt to remove ready-for-agent fails and that branch is skipped.
For each issue N:
gh issue edit N --remove-label ready-for-agent --add-label running. Comment a start line: ISO timestamp, runner identity, worktree path. If labelling fails because someone else already claimed it, skip to the next issue.git -C primary fetch origin main then git worktree add ../.workspaces/{repo}-{N} -b afk/{N}-{slug} origin/main from the primary checkout. The branch is local-only until push.{worktree}/.red/tmp/drop-{N}-{slug}.md using the template below. Create .red/tmp/ and append it to the worktree's .gitignore first if needed.:one:, :two:, :three:, :four: every 10 min (reset after :four:). Track PID in the state file so cleanup can kill it.runner-*.md with AGENT-PROMPT.md + the drop file + last 5 commits of main. Stream stdout into the loop's header tail. Detect stages by grep on the stream — see Stage Detection below.<promise>DONE</promise> → continue to feedback loops.<promise>BLOCKED</promise> plus notes appended to the drop file → comment the blocker on the issue, re-label ready-for-human, kill heartbeat, drop the worktree, go to next issue.<promise>NO MORE TASKS</promise> from inside one iteration → ignored. That sentinel is for the outer loop.EX_TEMPFAIL).pnpm test && pnpm typecheck && pnpm lint && pnpm build. Any missing script: skip it and note in the validation comment. Any failure: re-enter the inner agent with the failure output appended to the drop file's Notes. Cap at 2 retries before marking blocked.chore(afk): pre-merge snapshot for #N in primary. Never git stash. Never git checkout -- ..git -C primary merge --no-ff afk/{N}-{slug} -m "merge: #{N} {title}".git status as context, instructing it to fix conflicts in primary, then git commit. On still-conflicting: abort with git merge --abort, comment the diff on the issue, re-label ready-for-human, move on.git -C primary push origin main over SSH. Failure → comment, re-label ready-for-human, move on. Do not retry-loop indefinitely.gh issue close N --reason completed. Remove running label.git worktree remove ../.workspaces/{repo}-{N} and git branch -D afk/{N}-{slug} (the branch is already merged into main).finished {done}/{total} ({pct}%) — next: #{next}.Default behaviour is to alternate runners between issues (claude first, codex second, claude third, …) so the loop tolerates a single-runner outage without manual intervention. Override with --runner to pin one backend.
Exhaustion detection lives in runner-claude.md and runner-codex.md — they own the per-runner error strings. The orchestrator only sees RUNNER_EXHAUSTED as a structured signal.
When swap happens mid-issue, the same worktree and drop file are reused; the new runner sees the previous agent's Notes appended.
Background sub-shell, per-issue lifetime. State machine:
t=0 → claim comment
t=10 → :one:
t=20 → :two:
t=30 → :three:
t=40 → :four:
t=50 → :one: (reset)
...
Implementation: (while sleep 600; do gh issue comment N --body "$(next_glyph)"; done) &, PID saved to state. Killed on issue completion or blocker.
The terminal header has its own independent heartbeat counter (3 s tick) — see Live Header below. Don't conflate the two.
Inner agent stages, detected from stdout stream of the runner:
| stage | signal |
|---|---|
| setup | first output line |
| explore | git ls-files, find, repeated Read |
| impl | first Edit/Write call |
| tests | pnpm test invocation |
| commit | git commit invocation |
| merge | orchestrator stage, post-inner |
| push | orchestrator stage |
| close | orchestrator stage |
Each transition writes to state file. The monitor renders the current stage.
Redraw every 3 s on the controlling TTY, top of the scroll buffer. Use tput sc; tput cup 0 0; …; tput rc so the inner agent's stream below stays intact.
┌─ /afk ────────────────────────────────────────────────────┐
│ runner: codex elapsed: 00:14:23 eta: ~01:20:00 │
│ done: 3 / 12 (25%) blocked: 0 merged: 3 │
│ │
│ ▶ #142 wire OAuth callback │
│ worktree: ../.workspaces/red-skills-142 │
│ stage: impl heartbeat: :two: │
│ last: writing tests for callback handler │
│ │
│ queue: #143 #144 #145 #146 ... │
└────────────────────────────────────────────────────────────┘
If stdout is not a TTY (CI, piped log), skip header rendering and print one JSON line per state transition to stderr.
Path: .red/tmp/afk-state.json. Schema:
{
"version": 1,
"started_at": "2026-05-16T12:00:00-03:00",
"runner": "codex",
"filter": { "kind": "prd|issues|all", "value": "42" },
"total": 12,
"done": 3,
"failed": 0,
"blocked": 0,
"completed": [139, 140, 141],
"queue": [143, 144, 145, 146],
"current": {
"number": 142,
"title": "wire OAuth callback",
"slug": "wire-oauth-callback",
"worktree": "../.workspaces/red-skills-142",
"drop": ".red/tmp/drop-142-wire-oauth-callback.md",
"started_at": "2026-05-16T12:14:00-03:00",
"stage": "impl",
"heartbeat_glyph": ":two:",
"heartbeat_pid": 12345,
"runner": "codex",
"retries": 0,
"last_stream_line": "writing tests for callback handler"
},
"durations_seconds": [820, 940, 760]
}
Atomic write: write to afk-state.json.tmp, mv over the original. Monitor reads only.
.red/tmp/drop-{N}-{slug}.md:
# Issue #{N} — {title} [AFK]
source: {gh-url}
prd: {prd-url-or-issue-ref} # omit if none
runner: {claude|codex}
started: {iso8601}
attempt: {1..}
## Brief
{AGENT-BRIEF body from triage, verbatim}
## Acceptance
- [ ] {extracted from AGENT-BRIEF}
## Refs
- ADRs: {paths from brief, e.g. docs/adr/0007-foo.md}
- Wiki: {pages from brief, if any}
- PRD: {path or URL}
## Notes
{inner agent appends progress, blockers, decisions here across attempts}
The drop file follows the same minimalism as the handoff skill — reference artifacts by path, do not duplicate their content.
<promise>NO MORE TASKS</promise> → exit 0.-n N reached → summary + exit 0.After every issue, print:
✓ #142 wire OAuth callback 12m 14s tests:✓ lint:✓ types:✓ build:✓ merged b3f2a91
finished 4 / 12 (33%) — next: #143
After the loop, a final block:
/afk done.
runner : codex (3 issues), claude (1 issue)
duration : 01:14:22
processed : 4 closed, 0 blocked, 0 failed
remaining : 8 still ready-for-agent
See SAFETY.md. The orchestrator and the inner agent both inherit those rules. Violations abort the loop.
This skill is the single source of truth for autonomous execution in red-skills repos.
Searches MemPalace before answering questions about past work, people, projects, or prior decisions. Returns verbatim stored content instead of guessing from model memory.
Guides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Implements vector databases with Pinecone, Weaviate, Qdrant, Milvus, pgvector for semantic search, RAG, recommendations, and similarity systems. Optimizes embeddings, indexing, and hybrid search.
npx claudepluginhub reddb-io/red-skills --plugin brain