dev-actions-self-runner

Add self-hosted runner support with automatic fallback to GitHub-hosted runners in GitHub Actions workflows. Use when: (1) User wants to add self-hosted runner support, (2) User says 'self-hosted runner', 'add self runner', 'self-hosted fallback', (3) User wants to save GitHub Actions minutes.

6 stars

Best use case

dev-actions-self-runner is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Add self-hosted runner support with automatic fallback to GitHub-hosted runners in GitHub Actions workflows. Use when: (1) User wants to add self-hosted runner support, (2) User says 'self-hosted runner', 'add self runner', 'self-hosted fallback', (3) User wants to save GitHub Actions minutes.

Teams using dev-actions-self-runner should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/dev-actions-self-runner/SKILL.md --create-dirs "https://raw.githubusercontent.com/Takazudo/claude-resources/main/skills/dev-actions-self-runner/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/dev-actions-self-runner/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How dev-actions-self-runner Compares

Feature / Agentdev-actions-self-runnerStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Add self-hosted runner support with automatic fallback to GitHub-hosted runners in GitHub Actions workflows. Use when: (1) User wants to add self-hosted runner support, (2) User says 'self-hosted runner', 'add self runner', 'self-hosted fallback', (3) User wants to save GitHub Actions minutes.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Self-Hosted Runner with Fallback

Add a reusable `detect-runner.yml` workflow that checks if a self-hosted runner is online via GitHub API, then modify existing workflows to use it for heavy jobs while falling back to `ubuntu-latest` when offline.

## Step 1: Check Project Structure

Verify `.github/workflows/` exists and identify workflows to modify. Focus on **heavy jobs** (build, test, quality checks). Skip lightweight jobs (branch checks, notifications, deploys).

**Keep on `ubuntu-latest`:**

- Lightweight gate jobs (check-should-run, security checks)

**Special handling needed:**

- Jobs using `container:` (Docker) — works on WSL2 with Docker installed, but requires a permissions cleanup step (see [references/self-hosted-gotchas.md](references/self-hosted-gotchas.md))
- Deploy jobs using artifacts only (no checkout) — need workspace cleanup step due to stale files from prior jobs

## Step 2: Ask About Runner Registration Level

Ask the user: **"Is your self-hosted runner registered at the organization level or the repository level?"**

- **Organization level** (Settings > Actions > Runners at the org, shared with repos): Use the **org API** endpoint
- **Repository level** (Settings > Actions > Runners at the repo): Use the **repo API** endpoint

This determines both the API endpoint and the required token permissions.

| Level | API Endpoint | Token Permission |
| --- | --- | --- |
| **Org** | `/orgs/{org}/actions/runners` | Organization self-hosted runners: Read |
| **Repo** | `/repos/{owner}/{repo}/actions/runners` | Administration: Read-only |

## Step 3: Create detect-runner.yml

Create `.github/workflows/detect-runner.yml` using the appropriate API endpoint based on the user's answer in Step 2.

**For organization-level runners:**

```yaml
name: Detect Runner

# Reusable workflow to detect if a self-hosted runner is online.
# Falls back to ubuntu-latest if no runner is available or token is not set.
#
# Usage:
#   jobs:
#     detect-runner:
#       uses: ./.github/workflows/detect-runner.yml
#       secrets: inherit
#     my-job:
#       needs: detect-runner
#       runs-on: ${{ needs.detect-runner.outputs.runner }}
#
# Requires RUNNER_CHECK_TOKEN secret (fine-grained PAT with
# "Organization self-hosted runners: Read-only" permission).
on:
  workflow_call:
    outputs:
      runner:
        description: "Runner label to use (self-hosted or ubuntu-latest)"
        value: ${{ jobs.detect.outputs.runner }}

jobs:
  detect:
    name: Detect Runner
    runs-on: ubuntu-latest
    timeout-minutes: 2
    outputs:
      runner: ${{ steps.detect.outputs.runner }}
    steps:
      - name: Check for online self-hosted runner
        id: detect
        env:
          CHECK_TOKEN: ${{ secrets.RUNNER_CHECK_TOKEN }}
        run: |
          RUNNER_LABEL="ubuntu-latest"

          if [ -n "$CHECK_TOKEN" ]; then
            # Check org-level runners first, then repo-level
            ORG="${{ github.repository_owner }}"
            ONLINE=0

            for API_URL in \
              "https://api.github.com/orgs/${ORG}/actions/runners" \
              "https://api.github.com/repos/${{ github.repository }}/actions/runners"; do

              echo "Checking: $API_URL"
              RESPONSE=$(curl -s --max-time 10 -w "\n%{http_code}" \
                -H "Authorization: Bearer $CHECK_TOKEN" \
                -H "Accept: application/vnd.github+json" \
                -H "X-GitHub-Api-Version: 2022-11-28" \
                "$API_URL")

              HTTP_CODE=$(echo "$RESPONSE" | tail -1)
              BODY=$(echo "$RESPONSE" | sed '$d')

              if [ "$HTTP_CODE" = "200" ] && [ -n "$BODY" ]; then
                COUNT=$(echo "$BODY" | jq -r '[.runners[]? | select(.status == "online")] | length' 2>/dev/null)
                if [ -n "$COUNT" ] && [ "$COUNT" != "null" ] && [ "$COUNT" -gt 0 ]; then
                  ONLINE=$COUNT
                  echo "Found $ONLINE online runner(s)"
                  break
                fi
              else
                echo "API returned $HTTP_CODE, trying next"
              fi
            done

            if [ "$ONLINE" -gt 0 ]; then
              RUNNER_LABEL="self-hosted"
              echo "Self-hosted runner detected (online)"
            else
              echo "No self-hosted runners online, using ubuntu-latest"
            fi
          else
            echo "RUNNER_CHECK_TOKEN not set, using ubuntu-latest"
          fi

          echo "runner=$RUNNER_LABEL" >> "$GITHUB_OUTPUT"
          echo "Selected runner: $RUNNER_LABEL"
```

**For repository-level runners:** Use the same template but replace the API URL line with:

```yaml
              "https://api.github.com/repos/${{ github.repository }}/actions/runners")
```

And update the comment to: `# Requires RUNNER_CHECK_TOKEN secret (PAT with administration:read scope).`

## Step 4: Modify Existing Workflows

For each workflow, add the detect-runner call and update `runs-on`. By default, put all jobs on dynamic runner. If the user prefers, keep lightweight jobs (deploy, notify) on `ubuntu-latest`.

### Gate `actions/setup-node` and `actions/cache` to GH-hosted only

**On self-hosted runners these actions are pure overhead** — node is pre-installed and tool caches like `~/.cache/ms-playwright` or `~/.cache/pnpm` persist between runs naturally. But `actions/setup-node` will redownload/reextract node every run, and `actions/cache` will upload/download the cache to GitHub-hosted storage every run.

Real-world cost (zudo-pattern-gen run [#24927434497](https://github.com/zudolab/zudo-pattern-gen/actions/runs/24927434497/job/72999635846), self-hosted WSL2 runner that had degraded into a stuck state):

| Step | Cancelled run (`x0x-wsl2-zudolab-4`) | Healthy run (`x0x-wsl2-zudolab`) |
|---|---|---|
| `Setup Node.js` | **5m 58s** | 1s |
| `Cache Playwright browsers` (restore) | **10m 12s** | 1s |
| `Post Cache Playwright browsers` (save) | 24s (cancelled) | **5m 29s** every run |

Even on a healthy self-hosted runner, the post-cache save step burned ~5 min uploading 200MB for a directory that was already on disk. On the degraded runner the same steps appeared to hang.

**Pattern — gate both with the same `if:` used for `Install Playwright system deps (GH-hosted only)`:**

```yaml
# Self-hosted runners have node pre-installed; setup-node would
# redownload/reextract it every run.
- name: Setup Node.js (GH-hosted only)
  if: needs.detect-runner.outputs.runner == 'ubuntu-latest'
  uses: actions/setup-node@v5
  with:
    node-version: 22

# On GH-hosted, cache the browser binaries so reinstalling chromium only
# happens when the Playwright version bumps. On self-hosted runners,
# ~/.cache/ms-playwright persists between runs naturally — using
# actions/cache there costs ~10 min restore + ~5 min save uploading
# 200MB to GitHub for a directory that is already on disk.
- name: Cache Playwright browsers (GH-hosted only)
  if: needs.detect-runner.outputs.runner == 'ubuntu-latest'
  uses: actions/cache@v4
  with:
    path: ~/.cache/ms-playwright
    key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
    restore-keys: |
      ${{ runner.os }}-playwright-
```

Apply the same gate to any other `actions/cache` step whose `path:` is a tool cache that would naturally persist (Playwright, pnpm store, Cypress, Puppeteer, etc.). Project-source caches (e.g., `node_modules` build outputs that are populated by job steps) usually don't need this — they're not "naturally" present on a fresh checkout.

### Per-step `timeout-minutes` as a fail-fast safety net

Job-level `timeout-minutes: 25` lets a stuck cache or setup-node burn the full budget before the workflow gives up. For steps that have historically hung on degraded runners (`Setup Node.js`, `Cache Playwright browsers`, `pnpm install` on a corrupted store), add a tight per-step timeout so the workflow fails fast and a re-trigger lands on a healthy runner:

```yaml
- name: Cache Playwright browsers (GH-hosted only)
  if: needs.detect-runner.outputs.runner == 'ubuntu-latest'
  timeout-minutes: 3
  uses: actions/cache@v4
  # ...
```

Suggested values: 3–5 min for cache restore/save, 3 min for setup-node. If the step usually completes in <30s on a healthy runner, 3 min is generous. The worst case is one wasted run that fails fast instead of a 25 min hang plus a manual cancel.

### If a single self-hosted runner is consistently slow

The runner detection logic returns "any online runner" — it does not load-balance across multiple registered runners or detect degraded ones. If one specific runner (e.g., `x0x-wsl2-zudolab-4` in the example above) is consistently slower than its siblings, that is a host-level issue: check WSL2 disk/memory limits in `.wslconfig`, VHDX size and free space, and whether multiple runners on the same Windows host are competing for IO. Workflow-level gating + per-step timeouts make degraded runners survivable, but they don't fix the underlying host.

### Replacing Docker container jobs (e.g., Playwright)

If a workflow uses `container:` with a Docker image (e.g., `mcr.microsoft.com/playwright:v1.59.1-noble`), **replace it with direct tool installation**. Docker may not be available on self-hosted runners.

```yaml
# Before (Docker container):
e2e-tests:
  runs-on: ubuntu-latest
  container:
    image: mcr.microsoft.com/playwright:v1.59.1-noble
  steps:
    - run: pnpm install --frozen-lockfile
      env:
        PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1

# After (direct install with sudo-n pattern):
e2e-tests:
  needs: detect-runner
  runs-on: ${{ needs.detect-runner.outputs.runner }}
  steps:
    - run: pnpm install --frozen-lockfile
    - name: Install Playwright browsers
      run: |
        # --with-deps requires sudo for apt-get (GitHub-hosted has it, self-hosted may not)
        if sudo -n true 2>/dev/null; then
          pnpm exec playwright install --with-deps chromium
        else
          pnpm exec playwright install chromium
        fi
```

Also **remove any Playwright browser cache steps** (`actions/cache` with `~/.cache/ms-playwright`) — browsers persist on self-hosted runners naturally, and on GitHub-hosted the fresh download is fast enough (~30s).

### Removing cache maintenance workflows

If the project has a cache-maintenance workflow that exists solely to keep Playwright (or similar) caches alive, **delete it** — the caches are no longer needed.

### Multi-job workflows (build → deploy → notify)

```yaml
jobs:
  detect-runner:
    uses: ./.github/workflows/detect-runner.yml
    secrets: inherit

  build:
    needs: detect-runner
    runs-on: ${{ needs.detect-runner.outputs.runner }}
    # ... heavy build steps

  deploy:
    needs: [detect-runner, build]
    runs-on: ${{ needs.detect-runner.outputs.runner }}
    # ... deploy steps

  notify:
    needs: [detect-runner, build, deploy]
    runs-on: ${{ needs.detect-runner.outputs.runner }}
```

### Single-job workflows (build + deploy in one job)

The entire job gets the dynamic runner:

```yaml
jobs:
  detect-runner:
    uses: ./.github/workflows/detect-runner.yml
    secrets: inherit

  build-and-deploy:
    needs: detect-runner
    runs-on: ${{ needs.detect-runner.outputs.runner }}
    # ... build + deploy steps together
```

### With existing gate jobs

Add `detect-runner` as a parallel job alongside existing gates:

```yaml
jobs:
  check-should-run:
    # ... existing gate logic
  detect-runner:
    uses: ./.github/workflows/detect-runner.yml
    secrets: inherit

  build:
    needs: [check-should-run, detect-runner]
    runs-on: ${{ needs.detect-runner.outputs.runner }}
```

## Step 5: Ask About IFTTT Fallback Notification

Ask the user: **"Would you like to receive an IFTTT notification when the self-hosted runner is offline and CI falls back to ubuntu-latest?"**

If the user says **yes**, add a notification step to `detect-runner.yml` after the detect step:

```yaml
      - name: Notify IFTTT on fallback
        if: steps.detect.outputs.runner == 'ubuntu-latest' && env.IFTTT_PROD_NOTIFY != ''
        env:
          IFTTT_PROD_NOTIFY: ${{ secrets.IFTTT_PROD_NOTIFY }}
          SERVER_URL: ${{ github.server_url }}
          REPO: ${{ github.repository }}
          RUN_ID: ${{ github.run_id }}
        run: |
          RUN_URL="${SERVER_URL}/${REPO}/actions/runs/${RUN_ID}"
          curl -sSf --max-time 10 -X POST "$IFTTT_PROD_NOTIFY" \
            -H 'Content-Type: application/json' \
            -d "{
              \"value1\": \"$(echo $REPO | rev | cut -d/ -f1 | rev): self-hosted runner offline\",
              \"value2\": \"Falling back to ubuntu-latest\",
              \"value3\": \"${RUN_URL}\"
            }" || echo "::warning::IFTTT notification failed"
```

Then tell the user:

> To enable notifications, add your IFTTT Webhooks URL as a repo secret:
>
> 1. Go to https://ifttt.com/maker_webhooks → Documentation to find your webhook URL
> 2. Create a Webhooks applet that triggers on the event you choose
> 3. Add the webhook URL as a repo secret named `IFTTT_PROD_NOTIFY`:
>    - Settings → Secrets and variables → Actions → New repository secret
>    - Name: `IFTTT_PROD_NOTIFY`
>    - Value: `https://maker.ifttt.com/trigger/{event}/json/with/key/{your-key}`
>
> The notification sends three values: `value1` (status message), `value2` (detail), `value3` (run URL).
> Without the secret, the step is silently skipped.

If the user says **no**, skip this step.

## Step 6: Guide User Through Setup

After modifying workflows, inform the user of required setup:

1. **Register self-hosted runner**:
- **Org-level**: org Settings > Actions > Runners (shared with selected repos)
- **Repo-level**: repo Settings > Actions > Runners
2. **Create RUNNER_CHECK_TOKEN**: Fine-grained PAT with the appropriate scope:
- **Org-level runner**: `Organization self-hosted runners: Read` (under Organization permissions)
- **Repo-level runner**: `Administration: Read-only` (under Repository permissions)
3. **Add as repo secret**: Settings > Secrets > `RUNNER_CHECK_TOKEN` (add to each repo, or as an org secret)

Without `RUNNER_CHECK_TOKEN`, all jobs run on `ubuntu-latest` as before (safe default).

## Important Notes

- **Always call detect-runner unconditionally** — never skip it with `if:` conditions. The fallback handles all failure modes gracefully.
- **Cache keys differ by runner OS** — `runner.os` produces `Linux` on GitHub-hosted but may produce `macOS` or `Linux` on self-hosted depending on setup. Cache hits may not cross between them.
- **Replace `container:` jobs with direct tool install** — Docker may not be available on self-hosted runners. Use the `sudo -n` pattern for tools like Playwright that need system deps (see Step 4).
- **Single runner = single concurrent job** — parallel jobs need multiple runner instances registered in separate directories.
- **Never use `npx` in pnpm projects** — `npx` hangs on self-hosted runners. Use `./node_modules/.bin/<cmd>` or `pnpm dlx` instead (see gotchas).
- **`pnpm exec` only works in workspace members** — test fixtures with symlinked `node_modules` need direct bin paths instead.
- **Always clean stale `~/setup-pnpm` before `pnpm/action-setup`** — on self-hosted runners, `~/setup-pnpm` persists between runs and can cause `ENOTEMPTY` crashes. Add a cleanup step with `|| true` before every `pnpm/action-setup` invocation (even `rm -rf` itself can fail with ENOTEMPTY due to NFS lock files or held handles):

  ```yaml
  - name: Clean pnpm setup cache
    run: rm -rf ~/setup-pnpm ~/setup-pnpm-<slug> || true
  - uses: pnpm/action-setup@...
    with:
      version: 10
      dest: ~/setup-pnpm-<slug>
  ```

- **Use unique `dest:` per workflow** — when multiple workflows share the same self-hosted runner home directory, each must have a unique `dest:` to prevent concurrent runs from stomping on each other's pnpm installation. Convention: `~/setup-pnpm-{workflow-slug}`. For matrix/shard jobs, include the matrix variable: `~/setup-pnpm-{slug}-${{ matrix.shard }}`. Each cleanup step only removes `~/setup-pnpm` (legacy) and its own directory (see gotchas).
- **Prune pnpm store before install** — the persistent pnpm store on self-hosted runners can accumulate corrupted entries, causing `Worker pnpm#N exited with code 1` crashes. Add `pnpm store prune || true` before `pnpm install`:

  ```yaml
  - name: Install dependencies
    run: |
      pnpm store prune || true
      pnpm install --frozen-lockfile
  ```

For runner setup details (WSL2, systemd, auto-start), see [references/setup-guide.md](references/setup-guide.md).

For common pitfalls with self-hosted runners (Docker permissions, stale workspaces, pnpm store conflicts, concurrent pnpm dest conflicts, global install PATH issues), see [references/self-hosted-gotchas.md](references/self-hosted-gotchas.md).

Related Skills

gh-actions-wisdom

6
from Takazudo/claude-resources

GitHub Actions workflow best practices and pitfalls reference. Use when: (1) Writing or reviewing .yml workflows, (2) Setting up CI/CD pipelines, (3) Debugging slow, expensive, or stuck workflow runs, (4) User says 'gh actions', 'github actions', 'workflow best practices', (5) Before creating or modifying any .github/workflows/ file. Keywords: GitHub Actions, CI/CD, workflow, timeout, concurrency, security, caching.

dev-gh-actions-doc-auto-merge

6
from Takazudo/claude-resources

Create a GitHub Actions workflow that auto-merges a production branch into a documentation branch. Use when: (1) Setting up auto-sync from production to doc branch, (2) User mentions 'doc auto merge', 'auto sync docs', 'document branch sync', (3) User wants docs to stay up-to-date with production automatically.

zudoesa-articlify

6
from Takazudo/claude-resources

Convert conversation context into an esa article via the zudoesa-writer subagent. ONLY invoke when the user explicitly asks — NEVER proactively propose. Triggers: 'write esa article', 'esa記事', 'esaに書いて', 'articlify for esa', or /zudoesa-articlify. Gathers context, creates a writing brief, delegates to the writer subagent.

zudoesa-apply-voice

6
from Takazudo/claude-resources

Apply Takazudo's esa writing voice and vocabulary rules to text. Use when: (1) User wants to write/rewrite text in Takazudo's esa style, (2) User says 'apply voice', 'esa voice', 'esa文体で', 'esa風に書いて', '文体を適用', (3) User provides text to transform to esa style. Reads writing-style.md and vocabulary-rule.md from takazudo-esa-writing repo and applies the rules.

zudocg-articlify

6
from Takazudo/claude-resources

Convert conversation context into a CodeGrid article via the zudocg-writer subagent. ONLY invoke when the user explicitly asks — NEVER proactively propose. Triggers: 'write codegrid article', 'CodeGrid記事', 'codegridに書いて', 'articlify for codegrid', or /zudocg-articlify. Gathers context, creates a writing brief, delegates to the writer subagent.

zudocg-apply-voice

6
from Takazudo/claude-resources

Apply Takazudo's CodeGrid writing voice and vocabulary rules to text. Use when: (1) User wants to write/rewrite text in Takazudo's CodeGrid style, (2) User says 'apply voice', 'codegrid voice', 'codegrid文体で', 'codegrid風に書いて', '文体を適用', (3) User provides text to transform to CodeGrid style. Reads writing-style.md and vocabulary-rule.md from takazudo-codegrid-writing repo and applies the rules.

zpaper-articlify

6
from Takazudo/claude-resources

Convert conversation context into a zpaper blog article via the zpaper-writer subagent. ONLY invoke when the user explicitly asks — NEVER proactively propose. Triggers: 'write zpaper article', 'zpaper記事', 'zpaperに書いて', 'articlify for zpaper', or /zpaper-articlify. Gathers context, creates a writing brief, delegates to the writer subagent.

zpaper-apply-voice

6
from Takazudo/claude-resources

Apply Takazudo's zpaper blog writing voice and vocabulary rules to text. Use when: (1) User wants to write/rewrite text in Takazudo's zpaper style, (2) User says 'apply voice', 'zpaper voice', 'zpaper文体で', 'zpaper風に書いて', 'ブログ文体を適用', (3) User provides text to transform to zpaper style. Reads writing-style.md and vocabulary-rule.md from the zpaper repo and applies the rules.

xlsx

6
from Takazudo/claude-resources

Spreadsheet creation, editing, and analysis. Use when working with .xlsx, .xlsm, .csv, .tsv files for: (1) Creating spreadsheets with formulas and formatting, (2) Reading or analyzing data, (3) Modifying existing spreadsheets while preserving formulas, (4) Data analysis and visualization, (5) Recalculating formulas.

x

6
from Takazudo/claude-resources

Facade for development workflows. Routes on two axes: plan-first vs implement-now (escalates to /big-plan -a when the request needs research / decomposition / has unclear scope — the appended -a makes the plan chain into implementation in-session), then single vs multi on the ready-to-build fast paths (/x-as-pr single-topic, /x-wt-teams multi-topic parallel). Use when: (1) User says '/x' followed by dev instructions, (2) User wants to start development without choosing the workflow skill, (3) User says 'dev', 'implement', or 'build' with a task. Default option: -v (verify-ui). Review-loop (-l) is opt-in — without -l the downstream skill runs a single /deep-review pass. Forwards -a (autonomy/auto-chain) and -m (merge at the end + cleanup + CI watch) through every route; auto-fix of raised findings (-f) and issue-raising (-ri) are downstream defaults, with -nf/--no-fix and -nori/--no-raise-issues as the forwarded opt-outs. -a and -m are orthogonal — full hands-off end-to-end is -a -m.

x-wt-teams

6
from Takazudo/claude-resources

Parallel multi-topic development using git worktrees, base branches, and Claude Code agent teams. Use when: (1) User wants to work on multiple related features in parallel, (2) User mentions 'worktree', 'base branch', 'parallel development', 'split into topics', or 'multi-topic'. FULLY AUTONOMOUS — creates worktrees, spawns teams, coordinates everything. Also supports Super-Epic child mode for [Epic] issues from /big-plan with '**Super-epic:** #N' markers (targets the super-epic base branch instead of main).

x-as-pr

6
from Takazudo/claude-resources

Start a development workflow as a draft PR. Creates a NEW branch from the current branch, empty start commit, draft PR targeting the current branch, then implements. ALWAYS creates a new branch by default — produces a nested PR-on-PR when the current branch already has one. Use when: (1) User says 'dev as pr', (2) User wants a PR-first workflow before coding, (3) User passes -s/--stay to reuse the current branch instead of nesting, (4) User passes a GitHub issue URL to implement, (5) User passes --make-issue/--issue to create an issue first. Logs progress via issue comments when an issue is linked.