Skip to content
Latchkey

Cross-platform smoke test workflow (worldwonderer/oh-story-claudecode)

The Cross-platform smoke test workflow from worldwonderer/oh-story-claudecode, explained and optimized by Latchkey.

F

CI health: F - at risk

Point runs-on at Latchkey and get caching, run de-duplication, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.

Grade your own workflow free or run it on Latchkey →
Source: worldwonderer/oh-story-claudecode.github/workflows/cross-platform.ymlLicense MITView source

What it does

This is the Cross-platform smoke test workflow from the worldwonderer/oh-story-claudecode repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
name: Cross-platform smoke test
on: [push, pull_request]

jobs:
  static-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - uses: actions/setup-python@v5
        with:
          python-version: '3.x'
      - name: Run skill static check
        run: bash scripts/static-check.sh
      - name: Check hook-regex sync
        run: bash scripts/check-hook-regex-sync.sh
      - name: Check shared-file consistency
        run: bash scripts/check-shared-files.sh
      - name: AI-pattern detector regression
        run: bash scripts/test-ai-patterns.sh
      - name: Degeneration detector regression
        run: bash scripts/test-degeneration.sh
      - name: Prose backstop hook regression
        run: bash scripts/test-prose-backstop-hook.sh
      - name: Prose net 3-CLI parity
        run: bash scripts/test-prose-net-parity.sh
      - name: Story continuity backstop regression
        run: bash scripts/test-story-continuity.sh
      - name: Check story-setup deployment
        run: bash scripts/check-story-setup-deployment.sh
      - name: Check Codex adapter
        run: bash scripts/check-codex-adapter.sh
      - name: Check OpenCode adapter
        run: bash scripts/check-opencode-adapter.sh
      - name: Check OpenClaw skill compatibility
        run: bash scripts/check-openclaw-skills.sh
      - name: Test Codex hook adapter
        run: bash scripts/test-codex-hooks.sh
      - name: Guard against bare python3 invocations
        run: bash scripts/check-python-invocation.sh
      - name: Guard hook locale safety (LC_ALL=C + no full-width char classes)
        run: bash scripts/check-hook-locale-safety.sh
      # Generate a GBK-class locale so the hook test's Part 2 runs end-to-end here,
      # not just on macOS. Best-effort: if it fails the test self-skips Part 2.
      - name: Generate zh_CN.GBK locale (Chinese Windows simulation)
        run: sudo localedef -f GBK -i zh_CN zh_CN.GBK || sudo locale-gen zh_CN.GBK || true
      - name: Hook path-encoding portability (cp936 + real GBK locale)
        run: bash scripts/test-hook-encoding-portable.sh
      - name: Portable char-count (real interpreter)
        run: bash scripts/test-charcount-portable.sh
      - name: Portable char-count (simulated Windows Store stub)
        run: bash scripts/test-charcount-portable.sh --stub
      - name: Syntax-check collection scripts
        run: |
          for f in $(find skills -name '*-scraper.js' -o -name 'cdp-utils.js' -o -name 'setup-cdp-chrome.js'); do
            echo "node --check $f"
            node --check "$f"
          done

  windows:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - uses: actions/setup-python@v5
        with:
          python-version: '3.x'
      - name: AI-pattern detector regression
        shell: bash
        run: bash scripts/test-ai-patterns.sh
      - name: Degeneration detector regression
        shell: bash
        run: bash scripts/test-degeneration.sh
      - name: Prose backstop hook regression
        shell: bash
        run: bash scripts/test-prose-backstop-hook.sh
      - name: Prose net 3-CLI parity
        shell: bash
        run: bash scripts/test-prose-net-parity.sh
      - name: Story continuity backstop regression
        shell: bash
        run: bash scripts/test-story-continuity.sh
      - name: Test Codex hook adapter
        shell: bash
        run: bash scripts/test-codex-hooks.sh
      - name: Setup Chrome
        uses: browser-actions/setup-chrome@v1
        with:
          chrome-version: stable
      - name: Verify cdp-utils loads
        run: node -e "const u = require('./skills/story-short-scan/scripts/cdp-utils.js'); console.log('exports:', Object.keys(u));"
      - name: Verify sleep works
        run: node -e "const { sleep } = require('./skills/story-short-scan/scripts/cdp-utils.js'); const t0 = Date.now(); sleep(100); console.log('slept', Date.now()-t0, 'ms');"
      - name: Verify setup script dry-run
        run: node skills/browser-cdp/scripts/setup-cdp-chrome.js 9222 --dry-run
      # Run under Git Bash (shell: bash on windows-latest), matching how Claude Code
      # executes its Bash tool on Windows - this is where the python3 exit-49 bug bites.
      - name: Portable char-count (real interpreter)
        shell: bash
        run: bash scripts/test-charcount-portable.sh
      - name: Portable char-count (simulated Windows Store stub)
        shell: bash
        run: bash scripts/test-charcount-portable.sh --stub
      # Real Windows Git Bash path: the cp936 stdout bug (issue #164) bites here.
      - name: Hook path-encoding portability (cp936 + GBK locale if present)
        shell: bash
        run: bash scripts/test-hook-encoding-portable.sh

  macos:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - uses: actions/setup-python@v5
        with:
          python-version: '3.x'
      - name: AI-pattern detector regression
        run: bash scripts/test-ai-patterns.sh
      - name: Degeneration detector regression
        run: bash scripts/test-degeneration.sh
      - name: Prose backstop hook regression
        run: bash scripts/test-prose-backstop-hook.sh
      - name: Prose net 3-CLI parity
        run: bash scripts/test-prose-net-parity.sh
      - name: Story continuity backstop regression
        run: bash scripts/test-story-continuity.sh
      - name: Check Codex adapter
        run: bash scripts/check-codex-adapter.sh
      - name: Test Codex hook adapter
        run: bash scripts/test-codex-hooks.sh
      - name: Setup Chrome
        uses: browser-actions/setup-chrome@v1
        with:
          chrome-version: stable
      - name: Verify cdp-utils loads
        run: node -e "const u = require('./skills/story-short-scan/scripts/cdp-utils.js'); console.log('exports:', Object.keys(u));"
      - name: Verify sleep works
        run: node -e "const { sleep } = require('./skills/story-short-scan/scripts/cdp-utils.js'); const t0 = Date.now(); sleep(100); console.log('slept', Date.now()-t0, 'ms');"
      - name: Verify setup script dry-run
        run: node skills/browser-cdp/scripts/setup-cdp-chrome.js 9222 --dry-run
      - name: Portable char-count (real interpreter)
        run: bash scripts/test-charcount-portable.sh
      - name: Portable char-count (simulated Windows Store stub)
        run: bash scripts/test-charcount-portable.sh --stub
      - name: Hook path-encoding portability (cp936 + GBK locale if present)
        run: bash scripts/test-hook-encoding-portable.sh

The same workflow, on Latchkey

Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.

name: Cross-platform smoke test
on: [push, pull_request]
 
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
 
jobs:
  static-check:
    timeout-minutes: 30
    runs-on: latchkey-small
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          cache: 'npm'
          node-version: 20
      - uses: actions/setup-python@v5
        with:
          python-version: '3.x'
      - name: Run skill static check
        run: bash scripts/static-check.sh
      - name: Check hook-regex sync
        run: bash scripts/check-hook-regex-sync.sh
      - name: Check shared-file consistency
        run: bash scripts/check-shared-files.sh
      - name: AI-pattern detector regression
        run: bash scripts/test-ai-patterns.sh
      - name: Degeneration detector regression
        run: bash scripts/test-degeneration.sh
      - name: Prose backstop hook regression
        run: bash scripts/test-prose-backstop-hook.sh
      - name: Prose net 3-CLI parity
        run: bash scripts/test-prose-net-parity.sh
      - name: Story continuity backstop regression
        run: bash scripts/test-story-continuity.sh
      - name: Check story-setup deployment
        run: bash scripts/check-story-setup-deployment.sh
      - name: Check Codex adapter
        run: bash scripts/check-codex-adapter.sh
      - name: Check OpenCode adapter
        run: bash scripts/check-opencode-adapter.sh
      - name: Check OpenClaw skill compatibility
        run: bash scripts/check-openclaw-skills.sh
      - name: Test Codex hook adapter
        run: bash scripts/test-codex-hooks.sh
      - name: Guard against bare python3 invocations
        run: bash scripts/check-python-invocation.sh
      - name: Guard hook locale safety (LC_ALL=C + no full-width char classes)
        run: bash scripts/check-hook-locale-safety.sh
      # Generate a GBK-class locale so the hook test's Part 2 runs end-to-end here,
      # not just on macOS. Best-effort: if it fails the test self-skips Part 2.
      - name: Generate zh_CN.GBK locale (Chinese Windows simulation)
        run: sudo localedef -f GBK -i zh_CN zh_CN.GBK || sudo locale-gen zh_CN.GBK || true
      - name: Hook path-encoding portability (cp936 + real GBK locale)
        run: bash scripts/test-hook-encoding-portable.sh
      - name: Portable char-count (real interpreter)
        run: bash scripts/test-charcount-portable.sh
      - name: Portable char-count (simulated Windows Store stub)
        run: bash scripts/test-charcount-portable.sh --stub
      - name: Syntax-check collection scripts
        run: |
          for f in $(find skills -name '*-scraper.js' -o -name 'cdp-utils.js' -o -name 'setup-cdp-chrome.js'); do
            echo "node --check $f"
            node --check "$f"
          done
 
  windows:
    timeout-minutes: 30
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          cache: 'npm'
          node-version: 20
      - uses: actions/setup-python@v5
        with:
          python-version: '3.x'
      - name: AI-pattern detector regression
        shell: bash
        run: bash scripts/test-ai-patterns.sh
      - name: Degeneration detector regression
        shell: bash
        run: bash scripts/test-degeneration.sh
      - name: Prose backstop hook regression
        shell: bash
        run: bash scripts/test-prose-backstop-hook.sh
      - name: Prose net 3-CLI parity
        shell: bash
        run: bash scripts/test-prose-net-parity.sh
      - name: Story continuity backstop regression
        shell: bash
        run: bash scripts/test-story-continuity.sh
      - name: Test Codex hook adapter
        shell: bash
        run: bash scripts/test-codex-hooks.sh
      - name: Setup Chrome
        uses: browser-actions/setup-chrome@v1
        with:
          chrome-version: stable
      - name: Verify cdp-utils loads
        run: node -e "const u = require('./skills/story-short-scan/scripts/cdp-utils.js'); console.log('exports:', Object.keys(u));"
      - name: Verify sleep works
        run: node -e "const { sleep } = require('./skills/story-short-scan/scripts/cdp-utils.js'); const t0 = Date.now(); sleep(100); console.log('slept', Date.now()-t0, 'ms');"
      - name: Verify setup script dry-run
        run: node skills/browser-cdp/scripts/setup-cdp-chrome.js 9222 --dry-run
      # Run under Git Bash (shell: bash on windows-latest), matching how Claude Code
      # executes its Bash tool on Windows - this is where the python3 exit-49 bug bites.
      - name: Portable char-count (real interpreter)
        shell: bash
        run: bash scripts/test-charcount-portable.sh
      - name: Portable char-count (simulated Windows Store stub)
        shell: bash
        run: bash scripts/test-charcount-portable.sh --stub
      # Real Windows Git Bash path: the cp936 stdout bug (issue #164) bites here.
      - name: Hook path-encoding portability (cp936 + GBK locale if present)
        shell: bash
        run: bash scripts/test-hook-encoding-portable.sh
 
  macos:
    timeout-minutes: 30
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          cache: 'npm'
          node-version: 20
      - uses: actions/setup-python@v5
        with:
          python-version: '3.x'
      - name: AI-pattern detector regression
        run: bash scripts/test-ai-patterns.sh
      - name: Degeneration detector regression
        run: bash scripts/test-degeneration.sh
      - name: Prose backstop hook regression
        run: bash scripts/test-prose-backstop-hook.sh
      - name: Prose net 3-CLI parity
        run: bash scripts/test-prose-net-parity.sh
      - name: Story continuity backstop regression
        run: bash scripts/test-story-continuity.sh
      - name: Check Codex adapter
        run: bash scripts/check-codex-adapter.sh
      - name: Test Codex hook adapter
        run: bash scripts/test-codex-hooks.sh
      - name: Setup Chrome
        uses: browser-actions/setup-chrome@v1
        with:
          chrome-version: stable
      - name: Verify cdp-utils loads
        run: node -e "const u = require('./skills/story-short-scan/scripts/cdp-utils.js'); console.log('exports:', Object.keys(u));"
      - name: Verify sleep works
        run: node -e "const { sleep } = require('./skills/story-short-scan/scripts/cdp-utils.js'); const t0 = Date.now(); sleep(100); console.log('slept', Date.now()-t0, 'ms');"
      - name: Verify setup script dry-run
        run: node skills/browser-cdp/scripts/setup-cdp-chrome.js 9222 --dry-run
      - name: Portable char-count (real interpreter)
        run: bash scripts/test-charcount-portable.sh
      - name: Portable char-count (simulated Windows Store stub)
        run: bash scripts/test-charcount-portable.sh --stub
      - name: Hook path-encoding portability (cp936 + GBK locale if present)
        run: bash scripts/test-hook-encoding-portable.sh
 

What changed

1 third-party action is referenced by a movable tag. Pin it to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.

This workflow runs 3 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow