Skip to content
Development
Skill

/generate-runner

Generate a customized precommit runner for any ecosystem. Use when: non-Node projects need a runner, eject from generic runner, customize runner for project. Not for: running precommit (use /precommit), installing runner (handled by auto-install). Output: customized runner

From plugin
sd0x-dev-flow
195102 skills16 agents5 hooks

Claude Code

$ npx -y skills add sd0xdev/sd0x-harness --skill generate-runner --agent claude-code

SKILL.md

generate-runner.SKILL.md
name: generate-runner
description: "Generate a customized precommit runner for any ecosystem. Use when: non-Node projects need a runner, eject from generic runner, customize runner for project. Not for: running precommit (use /precommit), installing runner (handled by auto-install). Output: customized runner script with eject header."
allowed-tools: Read, Grep, Glob, Bash(node:*), Bash(chmod:*), Bash(bash:*), Write, AskUserQuestion

Generate Runner

Trigger

  • Keywords: generate runner, create runner, custom runner, eject runner, runner for python, runner for rust, runner for go

When NOT to Use

| Need | Use Instead | |------|-------------| | Run precommit checks | `/precommit` or `/precommit-fast` | | Install existing runner | `/project-setup` (auto-installs) | | Configure the shipped runner's lint globs | Check first that the runtime runner has no `@generated_at` header, then edit `.claude/runner-config.json` — and set `lintArgMode` for the same script role, or the globs stay inert (see § Lint Argument Injection) |

Lint Argument Injection

**Scope: the runners this plugin ships** — `scripts/precommit-runner.js` and `scripts/verify-runner.js`. What `/precommit`, `/precommit-fast` and `/verify` actually execute is the runtime copy at `.claude/scripts/*`, installed by `/install-scripts`. A runner **generated** by this skill is written to the same path but is user-owned: its template does not append lint arguments, so `lintGlobs` / `lintArgMode` have **no effect** on it. The discriminator is the eject header (§ Step 4) — all three of `@generated_at`, `@plugin_version`, `@template`, each on its own line with a value, in the opening comment block. Read the file before configuring it.

**Known limitation.** A project that installed a runner **before** this fix keeps running the old version, which passes ESLint-only flags into whatever lint script the repo declares — a file-rewriting non-ESLint linter reads them as paths and edits sources. Fixing the plugin source does not reach that copy, and detecting it reliably needs per-release provenance, which is deliberately out of scope. Remedy: **`/install-scripts precommit-runner.js verify-runner.js --force`**, with `--dry-run` first to read the write set (the installer copies "scripts + dependencies" without defining the closure, so the dry run is the authoritative list). The runners are named rather than swept in by `--all`, which would force-overwrite every core script; confirm `lib/utils.js` — where the fixed runners decide whether to inject — appears in the report.

**The shipped runner appends nothing to your lint script unless you ask it to.** `lintGlobs` alone does nothing; it needs `lintArgMode` for the same script role.

| Setting | Where | Shape | |---------|-------|-------| | `lintArgMode` | `.claude/runner-config.json`, or `package.json` → `sd0x` | `{"lint": "eslint"}` / `{"lint:fix": "none"}` — keyed by **script role**, never a bare string. Accepted values: `"eslint"` and `"none"` | | `lintGlobs` | same two places | `["src/**/*.{ts,tsx,js,jsx}", …]` — applied only when that role's `lintArgMode` is `"eslint"` |

**Precedence, per role**: `.claude/runner-config.json` first, **first valid value wins**; `package.json` → `sd0x` is the fallback. An unusable value — a bare string, a value outside `eslint`/`none`, a non-role-keyed shape — is warned about and falls through rather than latching, so `"none"` in `.claude` can suppress an opt-in `package.json` declares. (An unreadable `.claude/runner-config.json` warns via `loadLintGlobs()`; an unreadable `package.json` stays silent.)

In `package.json`, to inject ESLint's flags and globs into `lint:fix` only:

{ "sd0x": { "lintArgMode": { "lint:fix": "eslint" }, "lintGlobs": ["src/**/*.{ts,js}"] } }

`precommit` reads the `lint:fix` role; `verify` reads `lint` — keyed separately because a repo routinely runs different engines for each (this one runs markdownlint for `lint:fix`).

**Why it is opt-in.** The runner used to inject by default and guess from the script text whether the recipient was ESLint. markdownlint-cli2 treats every unrecognised argument as a file glob, so under `--fix` it rewrote JavaScript as Markdown; one run corrupted 71 files in this repo. Four successive detection grammars each misclassified something, so detection was removed rather than deepened.

Workflow

flowchart LR
    A[Detect Ecosystem] --> B[Select Template]
    B --> C[Customize]
    C --> D[Write Runner]
    D --> E[Verify]

Step 1: Detect Ecosystem

Scan project root for manifest files:

| Manifest | Ecosystem | Template ID | |----------|-----------|-------------| | `pnpm-lock.yaml` | Node.js (pnpm) | `node-pnpm` | | `yarn.lock` | Node.js (yarn) | `node-yarn` | | `package-lock.json` or `package.json` | Node.js (npm) | `node-npm` | | `pyproject.toml` | Python | `python` | | `Cargo.toml` | Rust | `rust` | | `go.mod` | Go | `go` |

If multiple detected, prefer Node.js > Python > Rust > Go. If none detected, ask user.

Step 2: Select Template

Load template from `references/templates.md` for the detected ecosystem.

Step 3: Customize

Read project-specific configuration:

| Source | What | |--------|------| | `package.json` scripts | Lint command, test command, build command | | `.claude/runner-config.json` | **Not read for lint configuration.** Neither `lintGlobs` nor `lintArgMode` reaches a generated runner — the template does not append lint arguments at all (§ Lint Argument Injection), so listing either here would present an inert value as a customization input | | Lock file | Package manager selection |

Step 4: Write Runner

Write to `.claude/scripts/precommit-runner.js` (Node) or `.claude/scripts/precommit-runner.sh` (non-Node).

> **A non-Node runner is generated for manual invocation, not for `/precommit`.** `/precommit`, > `/precommit-fast` and `/verify` probe the **`.js`** path only and execute it on existence; none of > them detects a `.sh

Read more
@sd0xdev
Ships withsd0x-dev-flow

Language: English | 繁體中文 | 简体中文 | 日本語 | 한국어 | Español The harness layer for Claude Code. Let the model choose the path. Keep "done" verifiable. Claude has discretion inside a closed, test-pinned anchor set.

195102 skills16 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
195
Star history of sd0xdev/sd0x-dev-flow on GitHub, a chart by star-history.com

Other skills on sd0x-dev-flow.

adr

adr

Write an Architecture Decision Record (ADR) for a feature — Context / Decision / Status / Consequences / Alternatives, filed as…

agentctl-setup

agentctl-setup

Install and set up the optional agentctl mod (task scope, refusal before execution, evidence that goes stale, model-free…

architecture

architecture

Architecture design and documentation. Produces 3-architecture.md with component diagrams, data flow, integration points, and…

ask

ask

Context-aware Q&A with auto context gathering. Use when: user has a quick question about codebase, git history, rules, docs, or…

best-practices

best-practices

Industry best practices conformance audit with mandatory adversarial debate. Produces audit artifact: verdict (OK/WARN/FAIL) +…

bug-fix

bug-fix

Bug fix workflow. Use when: fixing bugs, resolving issues, regression fixes. Not for: new features (use feature-dev),…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about generate-runner.

Which coding agents can use generate-runner?
generate-runner installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.