dev-blacksmith-migration

Migrate a repo's GitHub Actions CI from the self-hosted-with-fallback pattern (detect-runner reusable workflow + jobs that consume `${{ needs.detect-runner.outputs.runner }}`) to direct Blacksmith cloud runner labels. Use when: (1) User says 'blacksmith migration', 'migrate to blacksmith', 'switch to blacksmith', 'dev-blacksmith-migration', 'drop detect-runner', (2) Repo has `.github/workflows/detect-runner.yml` or any job using `runs-on: ${{ needs.<something>.outputs.runner }}`, (3) User wants to retire a self-hosted runner and rely fully on Blacksmith or another ephemeral cloud runner. Walks the gotchas — cross-instance cache miss, missing pnpm/Node setup in deploy-only jobs, container-job dubious-ownership, leftover `set-safe-directory: false` / Clean workspace / Fix workspace permissions steps.

6 stars

Best use case

dev-blacksmith-migration is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Migrate a repo's GitHub Actions CI from the self-hosted-with-fallback pattern (detect-runner reusable workflow + jobs that consume `${{ needs.detect-runner.outputs.runner }}`) to direct Blacksmith cloud runner labels. Use when: (1) User says 'blacksmith migration', 'migrate to blacksmith', 'switch to blacksmith', 'dev-blacksmith-migration', 'drop detect-runner', (2) Repo has `.github/workflows/detect-runner.yml` or any job using `runs-on: ${{ needs.<something>.outputs.runner }}`, (3) User wants to retire a self-hosted runner and rely fully on Blacksmith or another ephemeral cloud runner. Walks the gotchas — cross-instance cache miss, missing pnpm/Node setup in deploy-only jobs, container-job dubious-ownership, leftover `set-safe-directory: false` / Clean workspace / Fix workspace permissions steps.

Teams using dev-blacksmith-migration 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-blacksmith-migration/SKILL.md --create-dirs "https://raw.githubusercontent.com/Takazudo/claude-resources/main/skills/dev-blacksmith-migration/SKILL.md"

Manual Installation

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

How dev-blacksmith-migration Compares

Feature / Agentdev-blacksmith-migrationStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Migrate a repo's GitHub Actions CI from the self-hosted-with-fallback pattern (detect-runner reusable workflow + jobs that consume `${{ needs.detect-runner.outputs.runner }}`) to direct Blacksmith cloud runner labels. Use when: (1) User says 'blacksmith migration', 'migrate to blacksmith', 'switch to blacksmith', 'dev-blacksmith-migration', 'drop detect-runner', (2) Repo has `.github/workflows/detect-runner.yml` or any job using `runs-on: ${{ needs.<something>.outputs.runner }}`, (3) User wants to retire a self-hosted runner and rely fully on Blacksmith or another ephemeral cloud runner. Walks the gotchas — cross-instance cache miss, missing pnpm/Node setup in deploy-only jobs, container-job dubious-ownership, leftover `set-safe-directory: false` / Clean workspace / Fix workspace permissions steps.

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

# Blacksmith Migration

Migrate a repo from the "detect-runner with self-hosted fallback" CI pattern to direct [Blacksmith](https://blacksmith.sh/) cloud runner labels. The same playbook applies to other ephemeral cloud runner services (RunsOn, BuildJet, Namespace, Depot) — the runner-label syntax differs, the gotchas don't.

## When this skill triggers

The repo has at least one of:

- `.github/workflows/detect-runner.yml` (or similarly named) reusable workflow that polls the GitHub API for online self-hosted runners and emits a `runner` output
- Consumer jobs with `runs-on: ${{ needs.detect-runner.outputs.runner }}`
- Any `runs-on:` mixing `self-hosted` and `ubuntu-latest` via expressions
- `set-safe-directory: false` on `actions/checkout` (a self-hosted-only optimization)

If you don't see any of those, this skill is the wrong tool — the user just needs a normal `runs-on` label switch.

## Step 1: Audit the current state

Run the audit script to find every self-hosted-ism in `.github/workflows/`:

```bash
bash $HOME/.claude/skills/dev-blacksmith-migration/scripts/audit.sh
```

It prints, for each workflow file:

- `runs-on:` values (which need replacement)
- `detect-runner` references (job calls + `needs:` lists)
- `set-safe-directory: false` occurrences
- Manual `safe.directory` / `chown` / "Clean workspace" steps
- Jobs that use `container:` (these need extra care — see Step 6)
- Inter-job data sharing patterns (`actions/cache/save` → `actions/cache/restore` across jobs, or `actions/upload-artifact` → `download-artifact`)

Read the output before making any edits.

## Step 2: Ask the user the 2 decisions

Don't guess; ask. The answers determine which steps below to apply.

1. **Drop `detect-runner` entirely, or keep it as a fallback?**
- Default recommendation: drop it. Blacksmith replaces self-hosted; the polling job always sees zero online runners (Blacksmith instances are ephemeral and don't register in the org's self-hosted runners list), fires false alarms (e.g., IFTTT), and emits an `ubuntu-latest` output that consumers ignore once they hardcode the Blacksmith label.
- Keep only when there's a real mixed fleet: dedicated self-hosted runners that *do* register persistently, with Blacksmith as backup.

2. **What Blacksmith runner spec?**
- Default suggestion: `blacksmith-2vcpu-ubuntu-2204` (matches `ubuntu-latest`'s 2-vCPU shape). Bigger jobs may want `blacksmith-4vcpu-ubuntu-2204`, `blacksmith-8vcpu-ubuntu-2204`, etc. — confirm with the user.
- Ubuntu version: `ubuntu-2204` is the safe default. Use `ubuntu-2404` only if the workflow explicitly needs Ubuntu 24.04 features.
- ARM variant: append `-arm` (e.g. `blacksmith-2vcpu-ubuntu-2204-arm`) when targeting arm64 builds.

## Step 3: Replace `runs-on:` values

Every `runs-on:` value in `.github/workflows/` becomes (using the spec from Step 2):

```yaml
runs-on: blacksmith-2vcpu-ubuntu-2204
```

This includes:

- `runs-on: ${{ needs.detect-runner.outputs.runner }}` — replace
- `runs-on: ubuntu-latest` — replace (including the `detect` job inside `detect-runner.yml` itself if you're keeping the file)
- `runs-on: self-hosted` — replace
- `runs-on: runs-on=${{ github.run_id }}/runner=2cpu-linux-x64` (or any RunsOn label) — replace, if the repo went RunsOn → Blacksmith
- Any matrix or expression form that resolves to a GitHub-hosted, self-hosted, or other-provider label

Use `replace_all: true` on the Edit tool if all `runs-on:` values become identical.

## Step 4: Drop the `detect-runner` plumbing (if Step 2 #1 was "drop")

In each consumer workflow:

- Delete the `detect-runner:` job that calls `uses: ./.github/workflows/detect-runner.yml`
- Remove its surrounding comment block
- For every other job, drop `detect-runner` from the `needs:` list:
  - `needs: detect-runner` → remove the line entirely (job has no other deps)
  - `needs: [detect-runner, build]` → `needs: build`
  - `needs: [detect-runner, build, test]` → `needs: [build, test]`

Then `git rm .github/workflows/detect-runner.yml`.

The repo's `RUNNER_CHECK_TOKEN` GitHub Actions secret becomes orphan — tell the user it can be deleted manually if desired (you can't delete secrets via gh CLI without scope they may not want to grant).

If `detect-runner.yml` was emitting an IFTTT "self-hosted offline" notification, that goes away with the file. The deploy-status IFTTT notification (a separate job in the consumer workflow) is a *different concern* — leave that alone.

## Step 5: Fix self-hosted leftovers in remaining jobs

For every `actions/checkout` step:

```yaml
# Self-hosted leftover — REMOVE the with: block (or just the one option)
- uses: actions/checkout@<sha>
  with:
    set-safe-directory: false  # ← DELETE this option
```

Default `set-safe-directory: true` is required for container jobs to access the workspace. Leaving it `false` causes mysterious `fatal: detected dubious ownership` errors in container subprocesses.

Delete these step types if you find them — they're all "next-run cleanup" patterns that ephemeral runners don't need:

- `Clean workspace` (`rm -rf $GITHUB_WORKSPACE/...` before the rest of the job)
- `Fix workspace permissions` (`chown -R ... $GITHUB_WORKSPACE` at job end)
- Any step that "resets" or "prepares" the workspace before checkout

## Step 6: Container jobs need a manual safe.directory step (regardless of runner)

For any job that uses `container:` (not `runs-on:`), add this step *before* checkout:

```yaml
test:
  runs-on: blacksmith-2vcpu-ubuntu-2204
  container:
    image: mcr.microsoft.com/playwright:v1.58.2-noble
  steps:
    - name: Mark workspace as safe for git
      run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

    - uses: actions/checkout@<sha>
    # ... rest of the steps
```

**Why:** `actions/checkout` (a node action) writes safe.directory to `/root/.gitconfig` inside the container, but shell `run:` steps inside the same container have `HOME=/github/home` and read `/github/home/.gitconfig`. Without this step, lifecycle scripts like `pnpm install`'s `prepare` (which runs `lefthook install`, `husky install`, etc.) hit `fatal: detected dubious ownership in repository at '/__w/<repo>/<repo>'`.

This is **not** self-hosted-specific — it's a container-on-any-runner concern. The original codebase probably had this step alongside `set-safe-directory: false`, and the pair *looked* self-hosted-only. Keep this step; drop the `set-safe-directory: false`.

## Step 7: Inter-job data sharing — prefer artifacts on ephemeral runners

If the workflow has multiple jobs and shares files between them (typical Build → Test → Deploy split), audit the existing pattern:

- **`actions/cache/save` → `actions/cache/restore`** keyed by `${{ github.run_id }}`: works on a single self-hosted runner. Blacksmith provides an accelerated cache backend that survives across instances, but `actions/cache` was never designed as a job-to-job pipe — it's a "speed up next run" mechanism. Misusing it as inter-job transport is fragile (cache eviction, key collisions, container-network edge cases).
- **`actions/upload-artifact@v4` → `actions/download-artifact@v4`**: route through `api.github.com`, work cross-instance, work in containers, the documented inter-job transport.

**Recommended for any Blacksmith migration with multi-job workflows: switch to artifacts**.

Concrete swap (in the upstream job):

```yaml
# BEFORE
- name: Cache blog build output
  uses: actions/cache/save@<sha>
  with:
    path: blog/dist/
    key: blog-build-${{ github.run_id }}

# AFTER
- name: Upload blog build output
  uses: actions/upload-artifact@v4
  with:
    name: blog-dist
    path: blog/dist/
    retention-days: 1
    if-no-files-found: error
```

In the downstream jobs:

```yaml
# BEFORE
- name: Restore blog build cache
  uses: actions/cache/restore@<sha>
  with:
    path: blog/dist/
    key: blog-build-${{ github.run_id }}

# AFTER
- name: Download blog build output
  uses: actions/download-artifact@v4
  with:
    name: blog-dist
    path: blog/dist/
```

Blacksmith's accelerated `actions/cache` backend is fine to keep using for its intended purpose — speeding up `setup-node`, the pnpm store, and build-tool caches across runs. Just don't use it as an inter-job pipe within a single run.

## Step 8: Audit deploy-only jobs

Any job that does NOT have its own `actions/checkout` but DOES run commands like `pnpm`, `npm`, or `node` is a self-hosted leftover. On the persistent runner, the workspace and toolchain were inherited from a previous job; on ephemeral runners, each job starts on a fresh VM.

Symptom: `pnpm: command not found` in the deploy job after Build and Test pass.

Fix: add the missing setup steps at the top of the job:

```yaml
deploy:
  steps:
    - name: Checkout repository      # if the job needs package.json / pnpm-workspace.yaml
      uses: actions/checkout@<sha>

    - name: Setup pnpm
      uses: pnpm/action-setup@<sha>

    - name: Setup Node.js
      uses: actions/setup-node@<sha>
      with:
        node-version: <match the other jobs>

    # ... existing artifact downloads, deploy commands, etc.
```

If the deploy job runs `pnpm add -w <pkg>` or any command that needs a pnpm workspace, the `actions/checkout` is required (otherwise there's no `package.json` / `pnpm-workspace.yaml` for pnpm to find). Otherwise just the two setup steps may be enough.

## Step 9: Validate — beware the partial-validation trap

PR-level CI (often `pr-checks.yml`) usually runs a *single-job* preview-deploy workflow. **It cannot exercise the cross-job artifact passing or the container-job paths** that the production deploy uses. Pre-merge green on pr-checks is necessary but not sufficient.

The full validation requires merging to the trigger branch (usually `main`) and watching the production deploy. Plan for one or more iteration cycles directly on `main` if the user is OK with that, or coordinate via short-lived hotfix PRs.

For each push, watch CI with `/watch-ci <pr>` (PR mode) or `/watch-ci` (auto-detects the merged-PR path on the target branch).

## Common failure modes (one-liner fixes)

When a deploy fails post-merge, check the failing job's step name and match against the table below before re-reading logs in detail:

| Failing step output | Cause | Fix |
| --- | --- | --- |
| `Cache not found for input keys: ...-<run_id>` | `actions/cache` used as inter-job transport on ephemeral runners | Switch to artifacts (Step 7) |
| `pnpm: command not found` in deploy job | Deploy-only job missing setup steps | Add Setup pnpm + Setup Node.js (Step 8) |
| `fatal: detected dubious ownership in repository at '/__w/...'` | Container-job HOME mismatch between checkout and shell git | Add manual `safe.directory` step before checkout (Step 6) |
| `pnpm add -w <pkg>` errors with no `pnpm-workspace.yaml` found | Deploy job has no checkout | Add `actions/checkout` to the job (Step 8) |
| Build job's IFTTT alert "self-hosted runner offline" still firing | Old `detect-runner.yml` still in repo | `git rm` the workflow file (Step 4) |

For deeper context on each, see [references/troubleshooting.md](references/troubleshooting.md).

## Skill scope reminder

This skill is for the **migration**. Day-to-day GitHub Actions best practices (timeouts, concurrency, action pinning, security) live in `/gh-actions-wisdom`. Read both when starting a migration so you don't accidentally regress on those general rules while shuffling runner labels.

Related Skills

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.

watch-ci

6
from Takazudo/claude-resources

Watch GitHub PR CI checks in the background and notify on completion. Use when: (1) User wants to monitor CI/CD status, (2) User says 'watch CI', 'check CI', 'monitor checks', or 'wait for CI', (3) User wants to know when checks pass or fail. Runs a background gh polling shell loop (NOT a subagent — near-zero token cost), sends macOS notification on completion. Also handles merged PRs by watching the target branch CI.

w-update-wording-rule

6
from Takazudo/claude-resources

Add or update wording rules (表記ルール) in the w repo's vocabulary-rule.md files. Use when: (1) User says 'add wording rule', 'update wording rule', '表記ルール追加', (2) User wants to add a kanji/hiragana usage rule, (3) User provides a rule like 'X should be Y' with examples.