ワンクリックで
quality-ship
// Shared atom for running quality checks, committing, and pushing. Background knowledge for workflow commands -- not invoked directly.
// Shared atom for running quality checks, committing, and pushing. Background knowledge for workflow commands -- not invoked directly.
Full PR workflow -- ticket, branch, verify, lint, test, commit, push, open PR. Use when the user asks to open, ship, or land a PR; handles fresh work, mid-fix state, and changes already verified in the session.
Shared atom for analyzing a diff and writing a structured PR description. Background knowledge for workflow commands -- not invoked directly.
Root-cause-first debugging by tracing expected behavior to the first unintended side effect before changing contracts, parsing, or types. Use when debugging protocol errors, deserialization failures, null payloads, missing fields, restore or hydration issues, state-ownership bugs, unexpected requests, background mutations, or reviewing code where the visible failure may be downstream noise. Also loaded by /implement during bug-fix flows.
Control and navigate a logged-in macOS GUI session with upstream trycua/cua `cua-driver`. Use for macOS app automation, native dialogs, screenshots, UI inspection, clicking, typing, hotkeys, and any task where a Droid needs reliable computer-use control of macOS.
Reference for using linear-cli (aliased as `linear`) to manage Linear.app issues, projects, cycles, and sprints from the terminal. Use when the user mentions Linear tickets, issues, project management, or sprint planning.
Self-review your aggregate diff before shipping to catch dead weight, junk code, perf misses, pattern drift, AI slop, and scope creep. Use when the user asks to scrub, stranger-review, or clean up changes prior to opening a PR.
| name | quality-ship |
| description | Shared atom for running quality checks, committing, and pushing. Background knowledge for workflow commands -- not invoked directly. |
| user-invocable | false |
Before running any checks, determine if you're in a git worktree:
MAIN_REPO=$(git worktree list | head -1 | awk '{print $1}')
[ "$(git rev-parse --show-toplevel)" != "$MAIN_REPO" ] && echo "WORKTREE"
If in a worktree, follow the worktree-setup skill to symlink dependencies before proceeding. Never npm install or pip install in a worktree.
Detect the project's tooling from config files at the repo root, then run each applicable check:
| Check | Detection signals | Typical command |
|---|---|---|
| Format | .prettierrc*, biome.json, dprint.json | npm run format --write or npx prettier --write or equivalent |
| Lint fix | eslint.config*, .eslintrc*, biome.json | npm run fix or npx eslint --fix |
| Dead code (JS/TS) | knip.*, knip in package.json scripts | npm run knip or npx knip |
| Dead code (Python) | *.py in diff + pyproject.toml / setup.py | vulture <changed-paths> (or uvx vulture) |
| AI-slop (JS/TS) | any *.{js,jsx,ts,tsx} in diff | slop-scan delta <base> <head> --format json |
| React diagnostics (JS/TS) | react/react-dom/next/@remix-run/* in package.json | npx -y react-doctor@latest . --diff <base> --verbose |
| Type check | tsconfig.json | npm run typecheck or npx tsc --noEmit |
| Tests | jest.config*, vitest.config*, pytest.ini | Changed-file subset, serial workers (see below) |
package.json scripts (or pyproject.toml / Makefile for Python) for canonical commands (format, fix, lint, knip, test, typecheck).A failing validator is signal: assume it's right and fix the underlying code — remove the dead export knip found, narrow the type instead of casting, handle the swallowed error. Silencing it just ships the problem.
These escape hatches are last resorts, not default moves — reach for one only when the rule is a genuine false positive on that specific line, then scope it as narrowly as possible with a comment justifying why it's safe:
eslint-disable[-next-line] or per-rule config overridesignore / ignoreDependencies entries// @ts-ignore, // @ts-expect-error, looser tsconfig strictness# noqa, # type: ignore, vulture whitelists, # pragma: no cover.only / xfail on tests to force greenMandatory gate -- before committing, emit a checklist covering the worktree pre-check and every row in the table above:
quality-ship checklist:
- worktree: <main | repaired> (evidence)
- format: <ran | no signal> (evidence)
- lint: <ran | no signal> (evidence)
- dead-code: <ran | no signal> (evidence)
- ai-slop: <ran | no signal> (evidence)
- react: <ran | no signal> (evidence)
- typecheck: <ran | no signal> (evidence)
- tests: <ran | no signal> (evidence)
evidence = command run or missing config (validators); detection output + repair.py invocation (worktree). Don't commit until every line is filled. CI gates each validator; the worktree row catches repair gaps that surface as Cannot find module mid-validator. When detection emits WORKTREE, worktree: repaired is the only valid tag -- not "looks fine, skipped".
no signal means the tool is genuinely not configured in the repo — not that a convenient scoped script is missing. The absence of a pre-wired knip:cli task is never a reason to skip knip; scope it yourself with the tool's own flags (knip --workspace <pkg>, eslint <paths>, tsc -p <pkg>, vulture <paths>) or by running from the package dir. Skipping a configured validator because no scoped task exists is a bug, not a pass.
For any PR touching JS/TS files, run slop-scan delta <base-ref> <head-ref> --format json and triage the findings alongside lint/typecheck output. It catches the 15 deterministic slop patterns (swallowed errors, placeholder comments, generic Record<string, unknown> casts, pass-through wrappers, duplicate signatures, etc.) that lint and typecheck miss. Treat any new violations as blocking — do not commit slop.
For any PR touching a React codebase (signal: react/react-dom/next/@remix-run/* in package.json), run npx -y react-doctor@latest . --diff <base-ref> --verbose and triage alongside the AI-slop output. Different axes: slop-scan flags structural noise, react-doctor flags concrete React correctness/perf bugs (effect chains, derived state, fetch-in-effect, missing Suspense around useSearchParams, server-fn input validation, etc.). See the react-doctor skill for category-gated triage policy, false-positive handling, and config. New errors are blocking; warnings are blocking when the category is security, correctness, state-and-effects, or server -- advisory for design.
HARD RULE: never run a full test suite to validate a diff. No exceptions without an explicit reason logged in the checklist. A bare npm test / run test / turbo run test with no path argument is a defect — stop and re-scope before it runs. If you catch yourself about to execute an unscoped suite, that is the bug the user keeps yelling about.
Tests have two scope axes and you need both. The package filter (--workspace / turbo --filter) picks which suite; it does not narrow which tests — run test on a package still executes that package's entire suite (wiki, unrelated parsers, everything). Running the whole suite to validate a small diff is the mistake: slow, noisy, irrelevant. Every test invocation MUST carry a changed-file subset. No path argument = wrong command.
--findRelatedTests <changed src files> for import-graph-aware selection. Derive paths from git diff --name-only vs the base.| Runner | Serial flag |
|---|---|
| Jest | --runInBand (-i) |
| Vitest | --no-file-parallelism |
| Playwright | --workers=1 |
| pytest + xdist | -p no:xdist |
Forward flags + paths past the script/task boundary with --:
npm test -- --runInBand --findRelatedTests src/foo.ts
pnpm vitest run --no-file-parallelism src/foo.test.ts
turbo run test --filter=@app/web -- --runInBand src/foo.test.ts
Full-suite runs are CI's job, never yours. The only time you run a whole package suite locally is a genuinely cross-cutting change (shared util, config, or types imported by most of the package) — and when you do, you must say so explicitly in the checklist evidence (tests: full-suite (reason: <why>)). Absent that logged justification, a full-suite run is wrong.
Additional mitigations when concurrent droid activity is likely:
flock -w 600 /tmp/droid-tests.lock <cmd> — one test run at a time across droid instances.NODE_OPTIONS=--max-old-space-size=2048 — fail fast instead of swap-thrashing.nice -n 10 ionice -c3 when another runner is already active.In monorepos with turbo.json, always use turbo run <task> --filter=<package> instead of direct tool invocation for all checks: format, lint, knip, typecheck, and test. Direct invocation misses workspace-level configuration (path aliases, package-scoped configs) and runs against the entire repo unnecessarily. For test, the --filter only picks the package — append the changed-file subset after -- (see Test scoping), or you'll run the package's whole suite.
In monorepos without turbo, scope validators by run scope, not output filtering — pick the flag that limits what executes, not one that just filters logs of a full-repo run. Use git diff --name-only against the base to find affected packages, then:
npm run <task> --workspace=<pkg> (-w). Not --filter — npm's --filter only narrows reporter output while still running every workspace (pointlessly slow).pnpm --filter <pkg> run <task> (pnpm --filter does scope the run).yarn workspace <pkg> <task>.cd into the package dir and run there.git add -A
git commit -m "<type>(<scope>): <subject> (<TICKET-ID>)" -m "<body>"
fix, feat, refactor, docs, chore, test, etc. Subject <=72 chars, imperative ("add", not "added"). Reference the Linear ticket.git push -u origin HEAD
After pushing, check if a PR is already open for the current branch:
gh pr view --json number --jq '.number' 2>/dev/null
If a PR exists, follow the pr-description skill's post-push refresh flow (section 6): run the staleness check against the new diff, then the coherence pass only if updates are needed.