[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6WM5TDR2AXXKM643STTMPVF":3,"skill-same:01M6WM5TDR2AXXKM643STTMPVF":64},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":38,"linkOnly":39,"markdownContent":40,"markdownBody":41,"frontMatter":42,"refName":43,"commitSha":44,"skillDirectory":45,"forksCount":46,"repositoryHtmlUrl":47,"repositoryHomepageUrl":6,"ownerHtmlUrl":48,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":49,"install":50,"resources":63},"01M6WM5TDR2AXXKM643STTMPVF","self-hosted-runner-preflight",null,"Pre-flight checklist for self-hosted runner failures. Use when investigating low disk, missing runner, or stuck Green Gate on the $GITHUB_REPOSITORY fleet. Always verifies host-level container state, not just GitHub API.","jleechanorg\u002Fjleechan-skills","jleechanorg","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F221404966?v=4","01M6C1VJ99XG950X1DWPEBCBGX","01M6C1VJDK5YVDNT3362RT5WSB",6,"MIT","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fself-hosted-runners\u002Fskills\u002Fself-hosted-runner-preflight\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37],"self hosted","preflight","self","runner","self hosted runner preflight","when","github","for","missing","host","green","gate","self-hosted","container","use","just","disk","api","repository","state","2026-11-10 10:12:30",false,"---\nname: self-hosted-runner-preflight\ndescription: Pre-flight checklist for self-hosted runner failures. Use when investigating low disk, missing runner, or stuck Green Gate on the $GITHUB_REPOSITORY fleet. Always verifies host-level container state, not just GitHub API.\n---\n\n# Self-Hosted Runner Pre-Flight\n\n## When to use this skill\n- User says \"runner is offline\", \"runner missing\", \"CI failed low_disk_space\", \"Green Gate stuck\"\n- `gh api \"orgs\u002F$GITHUB_ORG\u002Factions\u002Frunners\"` shows fewer than the expected count\n  (`$RUNNER_EXPECTED_LINUX` + `$RUNNER_EXPECTED_MAC`)\n- A workflow run has been \"in_progress\" on Green Gate >30 minutes\n\n## Configuration\n\nRead these from the environment (see the plugin README); when one is unset, report\n`\u003CVAR> not configured` and stop rather than guessing a host or path.\n\n| Variable | Meaning |\n|---|---|\n| `GITHUB_ORG` | Org that owns the runners (default: `${GITHUB_REPOSITORY%%\u002F*}`) |\n| `RUNNER_HOST` | SSH alias of the Linux runner host |\n| `RUNNER_HOST_DOCKER_SOCK` | Docker socket on that host (default `unix:\u002F\u002F\u002Fvar\u002Frun\u002Fdocker.sock`) |\n| `RUNNER_COMPOSE_DIR` | docker-compose directory for the Linux runners on that host |\n| `RUNNER_INSTALL_DIR` | Local runner install root (default `${XDG_DATA_HOME:-$HOME\u002F.local\u002Fshare}\u002Fself-hosted-runners`) |\n| `RUNNER_EXPECTED_LINUX` \u002F `RUNNER_EXPECTED_MAC` | Expected online runner counts |\n\n## The 5-questions pre-flight (MANDATORY before any fix)\n\nFor each failure class, answer BEFORE proposing a fix:\n\n1. **What does GitHub say?**\n   `gh api \"orgs\u002F$GITHUB_ORG\u002Factions\u002Frunners?per_page=100\" --jq '.runners[] | {name,status,busy}'`\n2. **What does the host actually have?**\n   - mac: `docker ps --format \"{{.Names}}\\t{{.Status}}\" | grep org-runner-mac-`\n   - Linux host: `ssh \"$RUNNER_HOST\" \"DOCKER_HOST=${RUNNER_HOST_DOCKER_SOCK:-unix:\u002F\u002F\u002Fvar\u002Frun\u002Fdocker.sock} docker ps --format '{{.Names}}\\t{{.Status}}' | grep org-runner-\"`\n3. **What does the disk look like inside the container?**\n   `docker exec \u003Cname> df -Pk \u002F` — needs >=1GB free for preflight to pass.\n4. **Is the runner in restart loop?**\n   - `docker ps -a --format \"{{.Names}}\\t{{.Status}}\" | grep Restarting`\n   - If yes, check logs: `docker logs --tail 30 \u003Cname>` for 403\u002Fregistration errors.\n5. **Is Green Gate stuck?**\n   Check the run step \"Check smoke gate (gate 8)\" — if IN_PROGRESS >30min with no smoke runs on the branch, see Class C re-dispatch.\n\n## Installed CLI capability boundary\n\nBefore a workflow relies on a CLI, verify the installed executable selected by\nthe actual job environment: resolved path, version or executable hash, exact\nsubcommand and required flags, with original command\u002Fexit evidence. A supported\nsource checkout or capable stub is not installed capability proof. Reuse an\napplicable existing receipt rather than launching a duplicate job.\n\nInspect probe side effects first: even a lookup can create state directories.\nUse a verified non-mutating capability query or existing receipt where possible;\nif no permitted probe establishes support, report the capability as unverified.\nDo not change HOME\u002Fconfig\u002Fstate to hide a registered volume, bypass the canonical\nresolver, hard-code a temporary fallback, or install a replacement to clear a\nfailed probe. In particular, do not install a replacement under this preflight.\n\nIn the workflow owner's existing offline tests, include an\nunsupported-command negative case that fails closed and an\nuninitialized cleanup path. The negative case must stop before checkout\u002Fbuild\u002Fupload,\npreserve the original exit status and avoid cleanup against an unset or unowned\npath. A successful stub-only test qualifies the harness, not the installed CLI.\n\nIf upload already succeeded but reconciliation failed, preserve the release\nreceipts and reconcile the original upload receipt before any retry. Capability\nqualification grants no cleanup, restart, credential, installation or release\nauthority. Existing task-specific holds override any legacy recipe below.\n\n## Failure-class fixes\n\n### Class A: low_disk_space (>=1 runner has \u003C1GB free inside container)\n- ROOT FIX: edit `self-hosted-oss\u002Fpre-job-hook.sh` to add disk cleanup (fires on EVERY job, not periodic).\n- Pattern:\n  ```bash\n  AVAIL_KB=\"$(df -Pk \"${RUNNER_WORKDIR}\" 2>\u002Fdev\u002Fnull | awk 'NR==2 {print $4}')\"\n  if [[ \"$AVAIL_KB\" -lt \"$DISK_MIN_KB\" ]]; then\n    rm -rf \u002Froot\u002F.cache\u002Fpip\n    rm -rf \"${RUNNER_WORKDIR}\u002F\u003Crepo>\"\n  fi\n  ```\n- Set `DISK_MIN_KB=5242880` (5GB, 5x the preflight threshold).\n- Belt-and-suspenders: add a periodic launchd script (`mac-runner-disk-cleanup.sh` style).\n- Deploy: `bash self-hosted-oss\u002Finstall.sh` syncs to `$RUNNER_INSTALL_DIR\u002Fpre-job-hook.sh` (bind-mounted live — no restart needed).\n- VERIFY: `docker exec \u003Crunner> bash -c 'pgrep Runner.Worker'` returns empty (idle), then `df -Pk \u002F` shows >=5GB.\n\n### Class B: missing runner (compose defines N but only N-1 containers exist)\n- mac (ARM64): `RUNNER_COUNT=\u003CN> bash \"$RUNNER_INSTALL_DIR\u002Fstart-runner.sh\" start`\n- Linux host (X64):\n  `ssh \"$RUNNER_HOST\" \"cd \\\"$RUNNER_COMPOSE_DIR\\\" && DOCKER_HOST=${RUNNER_HOST_DOCKER_SOCK:-unix:\u002F\u002F\u002Fvar\u002Frun\u002Fdocker.sock} docker compose up -d runner-\u003CN>\"`\n- Then verify: `docker ps | grep runner-\u003CN>` and `gh api \"orgs\u002F$GITHUB_ORG\u002Factions\u002Frunners\" --jq '.runners[].name' | grep runner-\u003CN>`\n\n### Class C: Green Gate stuck on gate 8 (smoke)\n- Compare `SKEPTIC_GATE_TRIGGER` SHA pinned in PR comments to `gh pr view \u003CN> --json headRefOid`.\n- If mismatched, re-dispatch in order:\n  ```bash\n  gh workflow run \"MCP Smoke Tests\" --ref \u003Cbranch> -f pr_number=\u003CN>\n  gh workflow run \"Skeptic Self-Verify\" --ref \u003Cbranch> -f pr_number=\u003CN>\n  gh workflow run green-gate.yml --ref \u003Cbranch> -f pr_number=\u003CN> -f head_sha=\u003Csha>\n  ```\n- All 3 require `pr_number`; green-gate.yml ALSO requires `head_sha`.\n\n### Class D: token returns 403 from inside container\n- Confirm token length: `docker exec \u003Cname> bash -c 'echo ${#ACCESS_TOKEN}'` (should be ~40).\n- Test directly:\n  `docker exec \u003Cname> curl -X POST -H \"Authorization: token $ACCESS_TOKEN\" -H \"Accept: application\u002Fvnd.github+json\" \"https:\u002F\u002Fapi.github.com\u002Forgs\u002F$GITHUB_ORG\u002Factions\u002Frunners\u002Fregistration-token\"`\n- 201 → token fine, timing issue (config.sh ran before API ready), re-run start-runner.\n- 401\u002F403 → token bad\u002Fexpired, rotate `gh auth token` and re-deploy.\n\n### Class E: Linux runner host (`$RUNNER_HOST`) fully unreachable (\"host dark\")\n\n**Distinct from Class B\u002FD.** Those assume the runner *process* is broken and a\ndocker-level fix (restart, token rotate) will work. Class E is for when the\n**entire physical host** is unreachable — no SSH, no API response, nothing to\nrestart, and (per standing org policy) no smart-plug\u002FIPMI remote-power path to\neven attempt a hard reset. This class assumes an on-prem host with zero remote-power\naccess; this is a known, accepted limitation, not a gap to fix here.\n\n**Two-signal confirmation (MANDATORY before declaring \"host dark\")** — a\nsingle failed signal is not sufficient; the skill's own wifi\u002Fsubnet caveat\n(see `runner-health` SKILL.md) means SSH timeout alone is frequently a false\npositive when the operator is on a different network than the runner host:\n\n1. **Signal 1 — direct reachability from the operator's machine:**\n   ```bash\n   ssh -o ConnectTimeout=5 -o BatchMode=yes \"$RUNNER_HOST\" true; echo \"ssh_exit=$?\"\n   ping -c 2 -W 2 \"$RUNNER_HOST\"; echo \"ping_exit=$?\"\n   ```\n   A non-zero exit on both is necessary but NOT sufficient on its own (could\n   be local wifi\u002Fsubnet routing, not a dead host).\n\n2. **Signal 2 — GitHub API shows ALL Linux-host runners idle simultaneously:**\n   ```bash\n   gh api \"orgs\u002F$GITHUB_ORG\u002Factions\u002Frunners?per_page=100\" \\\n     --jq '.runners[] | select(.name | startswith(\"org-runner-\")) | select(.name | test(\"mac\") | not) | {name,status,busy}'\n   ```\n   If EVERY Linux (non-mac) runner shows `status:\"online\", busy:false` (or\n   `offline`) with none in-flight, combined with Signal 1's timeout, that is\n   the confirmed two-signal \"host dark\" verdict. (A prior incident also saw\n   `dig \"$RUNNER_HOST\"` \u002F `host \"$RUNNER_HOST\"` return NXDOMAIN — a bonus third\n   signal when local DNS is involved, but not required for the verdict.)\n\n   **Do NOT declare host-dark from Signal 1 alone.** If Signal 2 shows any\n   Linux runner `busy:true`, the host is alive and this is a network\u002Fwifi\n   false-positive — stop, do not proceed to the playbook below.\n\n**Playbook once both signals confirm host-dark:**\n- **Do:** accept degraded capacity — the fleet temporarily runs on mac\n  runners only (or whatever GitHub-hosted overflow lane exists, if one has\n  been separately designed and merged; check for a GitHub-hosted-failover\n  design before assuming one is live — this preflight skill does not\n  implement that lane itself).\n- **Do:** log the recurrence as a comment on the fleet's tracked host-freeze bead\n  (`\u003Chost-freeze-bead-id>`, if your fleet tracks one). Do NOT open a new bead per recurrence; add evidence (date,\n  two-signal output) as a comment so the P1 stays a single source of truth.\n  `br comments add --actor \u003Cyou> \u003Chost-freeze-bead-id> -- \"\u003Cdate>: host dark, ssh+api both confirmed...\"`\n- **Don't:** retry SSH in a tight loop hoping it comes back — the host has no\n  remote-power path, so nothing you run remotely will bring it back.\n  Wasted retries burn time that should go to capacity triage instead.\n- **Don't:** attempt any smart-plug\u002FIPMI\u002Fremote-power action — explicitly\n  deprioritized; this is a documentation\u002Ftriage gap, not a hardware-control\n  gap to fill.\n- **Escalation:** if the host has been dark for a threshold you care about\n  (this org's own SLA), the only real remediation is physical (someone at the\n  location power-cycles it). Note that in the bead comment rather than\n  attempting a workaround that doesn't exist yet.\n\n## Anti-patterns\n- Trusting GitHub UI as ground truth for runner health.\n- Proposing \"schedule a cron to clean up\" as the primary fix (use per-job hook).\n- Re-dispatching Green Gate without first dispatching smoke (gate 8 polls forever).\n- Restarting the container while a job is running (always check `pgrep Runner.Worker` first).\n- Editing the runtime mirror directly (`$RUNNER_INSTALL_DIR\u002F`) — edit `self-hosted-oss\u002F`, then `bash install.sh` to sync.\n- Declaring \"host dark\" (Class E) from a single SSH\u002Fping timeout — always confirm with the GitHub API signal too; SSH-only failure is frequently a wifi\u002Fsubnet false positive.\n- Retrying SSH to a confirmed-dark host in a tight loop — there is no remote-power path, so it will not come back on its own; spend the time on capacity triage and the host-freeze bead comment instead.\n- Opening a new bead for each host-dark recurrence — track the incident class on one bead and add a comment with the new date + two-signal evidence instead.\n\n","# Self-Hosted Runner Pre-Flight\n\n## When to use this skill\n- User says \"runner is offline\", \"runner missing\", \"CI failed low_disk_space\", \"Green Gate stuck\"\n- `gh api \"orgs\u002F$GITHUB_ORG\u002Factions\u002Frunners\"` shows fewer than the expected count\n  (`$RUNNER_EXPECTED_LINUX` + `$RUNNER_EXPECTED_MAC`)\n- A workflow run has been \"in_progress\" on Green Gate >30 minutes\n\n## Configuration\n\nRead these from the environment (see the plugin README); when one is unset, report\n`\u003CVAR> not configured` and stop rather than guessing a host or path.\n\n| Variable | Meaning |\n|---|---|\n| `GITHUB_ORG` | Org that owns the runners (default: `${GITHUB_REPOSITORY%%\u002F*}`) |\n| `RUNNER_HOST` | SSH alias of the Linux runner host |\n| `RUNNER_HOST_DOCKER_SOCK` | Docker socket on that host (default `unix:\u002F\u002F\u002Fvar\u002Frun\u002Fdocker.sock`) |\n| `RUNNER_COMPOSE_DIR` | docker-compose directory for the Linux runners on that host |\n| `RUNNER_INSTALL_DIR` | Local runner install root (default `${XDG_DATA_HOME:-$HOME\u002F.local\u002Fshare}\u002Fself-hosted-runners`) |\n| `RUNNER_EXPECTED_LINUX` \u002F `RUNNER_EXPECTED_MAC` | Expected online runner counts |\n\n## The 5-questions pre-flight (MANDATORY before any fix)\n\nFor each failure class, answer BEFORE proposing a fix:\n\n1. **What does GitHub say?**\n   `gh api \"orgs\u002F$GITHUB_ORG\u002Factions\u002Frunners?per_page=100\" --jq '.runners[] | {name,status,busy}'`\n2. **What does the host actually have?**\n   - mac: `docker ps --format \"{{.Names}}\\t{{.Status}}\" | grep org-runner-mac-`\n   - Linux host: `ssh \"$RUNNER_HOST\" \"DOCKER_HOST=${RUNNER_HOST_DOCKER_SOCK:-unix:\u002F\u002F\u002Fvar\u002Frun\u002Fdocker.sock} docker ps --format '{{.Names}}\\t{{.Status}}' | grep org-runner-\"`\n3. **What does the disk look like inside the container?**\n   `docker exec \u003Cname> df -Pk \u002F` — needs >=1GB free for preflight to pass.\n4. **Is the runner in restart loop?**\n   - `docker ps -a --format \"{{.Names}}\\t{{.Status}}\" | grep Restarting`\n   - If yes, check logs: `docker logs --tail 30 \u003Cname>` for 403\u002Fregistration errors.\n5. **Is Green Gate stuck?**\n   Check the run step \"Check smoke gate (gate 8)\" — if IN_PROGRESS >30min with no smoke runs on the branch, see Class C re-dispatch.\n\n## Installed CLI capability boundary\n\nBefore a workflow relies on a CLI, verify the installed executable selected by\nthe actual job environment: resolved path, version or executable hash, exact\nsubcommand and required flags, with original command\u002Fexit evidence. A supported\nsource checkout or capable stub is not installed capability proof. Reuse an\napplicable existing receipt rather than launching a duplicate job.\n\nInspect probe side effects first: even a lookup can create state directories.\nUse a verified non-mutating capability query or existing receipt where possible;\nif no permitted probe establishes support, report the capability as unverified.\nDo not change HOME\u002Fconfig\u002Fstate to hide a registered volume, bypass the canonical\nresolver, hard-code a temporary fallback, or install a replacement to clear a\nfailed probe. In particular, do not install a replacement under this preflight.\n\nIn the workflow owner's existing offline tests, include an\nunsupported-command negative case that fails closed and an\nuninitialized cleanup path. The negative case must stop before checkout\u002Fbuild\u002Fupload,\npreserve the original exit status and avoid cleanup against an unset or unowned\npath. A successful stub-only test qualifies the harness, not the installed CLI.\n\nIf upload already succeeded but reconciliation failed, preserve the release\nreceipts and reconcile the original upload receipt before any retry. Capability\nqualification grants no cleanup, restart, credential, installation or release\nauthority. Existing task-specific holds override any legacy recipe below.\n\n## Failure-class fixes\n\n### Class A: low_disk_space (>=1 runner has \u003C1GB free inside container)\n- ROOT FIX: edit `self-hosted-oss\u002Fpre-job-hook.sh` to add disk cleanup (fires on EVERY job, not periodic).\n- Pattern:\n  ```bash\n  AVAIL_KB=\"$(df -Pk \"${RUNNER_WORKDIR}\" 2>\u002Fdev\u002Fnull | awk 'NR==2 {print $4}')\"\n  if [[ \"$AVAIL_KB\" -lt \"$DISK_MIN_KB\" ]]; then\n    rm -rf \u002Froot\u002F.cache\u002Fpip\n    rm -rf \"${RUNNER_WORKDIR}\u002F\u003Crepo>\"\n  fi\n  ```\n- Set `DISK_MIN_KB=5242880` (5GB, 5x the preflight threshold).\n- Belt-and-suspenders: add a periodic launchd script (`mac-runner-disk-cleanup.sh` style).\n- Deploy: `bash self-hosted-oss\u002Finstall.sh` syncs to `$RUNNER_INSTALL_DIR\u002Fpre-job-hook.sh` (bind-mounted live — no restart needed).\n- VERIFY: `docker exec \u003Crunner> bash -c 'pgrep Runner.Worker'` returns empty (idle), then `df -Pk \u002F` shows >=5GB.\n\n### Class B: missing runner (compose defines N but only N-1 containers exist)\n- mac (ARM64): `RUNNER_COUNT=\u003CN> bash \"$RUNNER_INSTALL_DIR\u002Fstart-runner.sh\" start`\n- Linux host (X64):\n  `ssh \"$RUNNER_HOST\" \"cd \\\"$RUNNER_COMPOSE_DIR\\\" && DOCKER_HOST=${RUNNER_HOST_DOCKER_SOCK:-unix:\u002F\u002F\u002Fvar\u002Frun\u002Fdocker.sock} docker compose up -d runner-\u003CN>\"`\n- Then verify: `docker ps | grep runner-\u003CN>` and `gh api \"orgs\u002F$GITHUB_ORG\u002Factions\u002Frunners\" --jq '.runners[].name' | grep runner-\u003CN>`\n\n### Class C: Green Gate stuck on gate 8 (smoke)\n- Compare `SKEPTIC_GATE_TRIGGER` SHA pinned in PR comments to `gh pr view \u003CN> --json headRefOid`.\n- If mismatched, re-dispatch in order:\n  ```bash\n  gh workflow run \"MCP Smoke Tests\" --ref \u003Cbranch> -f pr_number=\u003CN>\n  gh workflow run \"Skeptic Self-Verify\" --ref \u003Cbranch> -f pr_number=\u003CN>\n  gh workflow run green-gate.yml --ref \u003Cbranch> -f pr_number=\u003CN> -f head_sha=\u003Csha>\n  ```\n- All 3 require `pr_number`; green-gate.yml ALSO requires `head_sha`.\n\n### Class D: token returns 403 from inside container\n- Confirm token length: `docker exec \u003Cname> bash -c 'echo ${#ACCESS_TOKEN}'` (should be ~40).\n- Test directly:\n  `docker exec \u003Cname> curl -X POST -H \"Authorization: token $ACCESS_TOKEN\" -H \"Accept: application\u002Fvnd.github+json\" \"https:\u002F\u002Fapi.github.com\u002Forgs\u002F$GITHUB_ORG\u002Factions\u002Frunners\u002Fregistration-token\"`\n- 201 → token fine, timing issue (config.sh ran before API ready), re-run start-runner.\n- 401\u002F403 → token bad\u002Fexpired, rotate `gh auth token` and re-deploy.\n\n### Class E: Linux runner host (`$RUNNER_HOST`) fully unreachable (\"host dark\")\n\n**Distinct from Class B\u002FD.** Those assume the runner *process* is broken and a\ndocker-level fix (restart, token rotate) will work. Class E is for when the\n**entire physical host** is unreachable — no SSH, no API response, nothing to\nrestart, and (per standing org policy) no smart-plug\u002FIPMI remote-power path to\neven attempt a hard reset. This class assumes an on-prem host with zero remote-power\naccess; this is a known, accepted limitation, not a gap to fix here.\n\n**Two-signal confirmation (MANDATORY before declaring \"host dark\")** — a\nsingle failed signal is not sufficient; the skill's own wifi\u002Fsubnet caveat\n(see `runner-health` SKILL.md) means SSH timeout alone is frequently a false\npositive when the operator is on a different network than the runner host:\n\n1. **Signal 1 — direct reachability from the operator's machine:**\n   ```bash\n   ssh -o ConnectTimeout=5 -o BatchMode=yes \"$RUNNER_HOST\" true; echo \"ssh_exit=$?\"\n   ping -c 2 -W 2 \"$RUNNER_HOST\"; echo \"ping_exit=$?\"\n   ```\n   A non-zero exit on both is necessary but NOT sufficient on its own (could\n   be local wifi\u002Fsubnet routing, not a dead host).\n\n2. **Signal 2 — GitHub API shows ALL Linux-host runners idle simultaneously:**\n   ```bash\n   gh api \"orgs\u002F$GITHUB_ORG\u002Factions\u002Frunners?per_page=100\" \\\n     --jq '.runners[] | select(.name | startswith(\"org-runner-\")) | select(.name | test(\"mac\") | not) | {name,status,busy}'\n   ```\n   If EVERY Linux (non-mac) runner shows `status:\"online\", busy:false` (or\n   `offline`) with none in-flight, combined with Signal 1's timeout, that is\n   the confirmed two-signal \"host dark\" verdict. (A prior incident also saw\n   `dig \"$RUNNER_HOST\"` \u002F `host \"$RUNNER_HOST\"` return NXDOMAIN — a bonus third\n   signal when local DNS is involved, but not required for the verdict.)\n\n   **Do NOT declare host-dark from Signal 1 alone.** If Signal 2 shows any\n   Linux runner `busy:true`, the host is alive and this is a network\u002Fwifi\n   false-positive — stop, do not proceed to the playbook below.\n\n**Playbook once both signals confirm host-dark:**\n- **Do:** accept degraded capacity — the fleet temporarily runs on mac\n  runners only (or whatever GitHub-hosted overflow lane exists, if one has\n  been separately designed and merged; check for a GitHub-hosted-failover\n  design before assuming one is live — this preflight skill does not\n  implement that lane itself).\n- **Do:** log the recurrence as a comment on the fleet's tracked host-freeze bead\n  (`\u003Chost-freeze-bead-id>`, if your fleet tracks one). Do NOT open a new bead per recurrence; add evidence (date,\n  two-signal output) as a comment so the P1 stays a single source of truth.\n  `br comments add --actor \u003Cyou> \u003Chost-freeze-bead-id> -- \"\u003Cdate>: host dark, ssh+api both confirmed...\"`\n- **Don't:** retry SSH in a tight loop hoping it comes back — the host has no\n  remote-power path, so nothing you run remotely will bring it back.\n  Wasted retries burn time that should go to capacity triage instead.\n- **Don't:** attempt any smart-plug\u002FIPMI\u002Fremote-power action — explicitly\n  deprioritized; this is a documentation\u002Ftriage gap, not a hardware-control\n  gap to fill.\n- **Escalation:** if the host has been dark for a threshold you care about\n  (this org's own SLA), the only real remediation is physical (someone at the\n  location power-cycles it). Note that in the bead comment rather than\n  attempting a workaround that doesn't exist yet.\n\n## Anti-patterns\n- Trusting GitHub UI as ground truth for runner health.\n- Proposing \"schedule a cron to clean up\" as the primary fix (use per-job hook).\n- Re-dispatching Green Gate without first dispatching smoke (gate 8 polls forever).\n- Restarting the container while a job is running (always check `pgrep Runner.Worker` first).\n- Editing the runtime mirror directly (`$RUNNER_INSTALL_DIR\u002F`) — edit `self-hosted-oss\u002F`, then `bash install.sh` to sync.\n- Declaring \"host dark\" (Class E) from a single SSH\u002Fping timeout — always confirm with the GitHub API signal too; SSH-only failure is frequently a wifi\u002Fsubnet false positive.\n- Retrying SSH to a confirmed-dark host in a tight loop — there is no remote-power path, so it will not come back on its own; spend the time on capacity triage and the host-freeze bead comment instead.\n- Opening a new bead for each host-dark recurrence — track the incident class on one bead and add a comment with the new date + two-signal evidence instead.\n\n",{"name":5,"description":7},"main","8144f00ebafc4306264c63239e4b9fa42e48a90e","plugins\u002Fself-hosted-runners\u002Fskills\u002Fself-hosted-runner-preflight",0,"https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills","https:\u002F\u002Fgithub.com\u002Fjleechanorg","2026-11-12 14:45:07",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add jleechanorg\u002Fjleechan-skills --skill self-hosted-runner-preflight",{"tool":56,"command":57},"bunx","bunx skills add jleechanorg\u002Fjleechan-skills --skill self-hosted-runner-preflight",{"tool":59,"command":60},"pnpm","pnpm dlx skills add jleechanorg\u002Fjleechan-skills --skill self-hosted-runner-preflight","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fself-hosted-runners\u002Fskills\u002Fself-hosted-runner-preflight\u002FSKILL.md",true,[],[65,81,101,114,128,144],{"skillNo":66,"name":67,"nameZh":6,"description":68,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":69,"categories":70,"keywords":71,"publishedAt":38},"01M716Y5MTJ6GYJZ2ATXCJK8G4","instinct","Use when the user invokes \u002Finstinct or \u002Fin, or asks to \"message Instinct\", \"ask Instinct\", \"tell Instinct\", \"check Instinct\", or read replies from the configured peer assistant. iMessage first, WhatsApp Web as fallback.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Finstinct\u002FSKILL.md",[],[67,72,23,73,74,32,75,76,77,78,79,80],"user","replies","check","identity","whatsapp","gmail","read","message","ask",{"skillNo":82,"name":83,"nameZh":6,"description":84,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":92,"publishedAt":38},"01M716Y4HF7FVVMJSA2CCVN5VF","hr","Compatibility alias for history-resume; produce the same fresh-state, provenance-aware resume briefing.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fhr\u002FSKILL.md",[87],{"categoryNo":88,"categoryName":89,"taxonomyType":90,"taxonomyTypeDesc":91},"01JBSEEDCAT000000000000038","人力资源","PROFESSION","适用职业",[83,93,94,95,25,96,97,98,99,37,100],"resume","compatibility","provenance","history","produce","alias","briefing","fresh",{"skillNo":102,"name":103,"nameZh":6,"description":104,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":105,"categories":106,"keywords":108,"publishedAt":38},"01M716Y1FFNFKFJYYKF8HQA6T8","history-resume","Resume briefing for the current repository branch or worktree using fresh state and admitted history sources.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fhistory-resume\u002FSKILL.md",[107],{"categoryNo":88,"categoryName":89,"taxonomyType":90,"taxonomyTypeDesc":91},[96,93,109,110,72,111,99,36,25,112,113,37,100],"history resume","branch","analysis","worktree","sources",{"skillNo":115,"name":116,"nameZh":6,"description":117,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":118,"categories":119,"keywords":120,"publishedAt":38},"01M716XWXJ8EPHK4RH9T14TR85","grok","Alias for the canonical grokbot browser conversation workflow; \u002Fgrok talks to the Grok bot the same way \u002Fdot talks to Dot.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fgrok\u002FSKILL.md",[],[116,121,122,123,25,124,98,125,126,127],"dot","bot","workflow","canonical","conversation","browser","grokbot",{"skillNo":129,"name":130,"nameZh":6,"description":131,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":132,"categories":133,"keywords":134,"publishedAt":38},"01M70N9Q07DTE0EW5KFXMMMSJ0","codexa-bench","Compare `codexa` and normal `codex` on a fair split of comparable work by default; use `--strict` for duplicate runs of the exact same task.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fcodexa-bench\u002FSKILL.md",[],[135,136,137,32,138,25,139,140,141,142,143],"codexa bench","work","split","default","duplicate","task","compare","normal","codex",{"skillNo":145,"name":146,"nameZh":6,"description":147,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":148,"licenseFileUrl":149,"sourceHtmlUrl":150,"categories":151,"keywords":163,"publishedAt":38},"01M6C24S2X60SP8BBFGAEKPEGW","frontend-design","Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML\u002FCSS layouts, or when styling\u002Fbeautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Ffrontend-design\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Ffrontend-design\u002FSKILL.md",[152,157,160],{"categoryNo":153,"categoryName":154,"taxonomyType":155,"taxonomyTypeDesc":156},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",{"categoryNo":158,"categoryName":159,"taxonomyType":155,"taxonomyTypeDesc":156},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":161,"categoryName":162,"taxonomyType":90,"taxonomyTypeDesc":91},"01JBSEEDCAT000000000000032","设计师",[164,165,166,32,167,168,169,72,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,23,188],"frontend","design","frontend design","generic","ui design","react","html","components","code","artifacts","ui","aesthetics","Production","web components","landing","applications","quality","web","css","create","examples","with","react components","web ui","pages"]