/my-ship-it
Pre-commit gate. Stops you from shipping broken or sloppy code without permission, but does not take the action for you.
When to invoke
Trigger phrases (case-insensitive): /my-ship-it, ship it, ship this. Run only when there's an active diff in the current repo.
If there is no diff (git status --porcelain empty), say so in one line and stop.
Pipeline — execute in order, do not skip
Step 1 — Detect project tooling
Probe the repo root. Pick the first match:
| File present | Test command | Lint command |
|---|---|---|
package.json with a test script |
npm test --silent (or pnpm test/yarn test if those lockfiles exist) |
npm run lint --silent if a lint script exists |
pyproject.toml or pytest.ini or tests/ |
pytest -q |
ruff check . if ruff is installed, else flake8 . if installed, else skip |
go.mod |
go test ./... |
go vet ./... |
Cargo.toml |
cargo test --quiet |
cargo clippy --quiet -- -D warnings |
Gemfile |
bundle exec rspec if rspec present, else bundle exec rake test |
bundle exec rubocop if installed, else skip |
If nothing matches, stop with a one-line message: ship-it: no recognized test runner — verify manually before committing.
Step 2 — Run lint and tests in parallel
Single message, two Bash calls in parallel: lint and test. Use a generous timeout (up to 600000 ms).
- If either fails: print only the failing block (last ~40 lines), do NOT print the passing block, and stop. Verdict:
REQUEST CHANGES — fix tests/lint and rerun /my-ship-it. - If lint isn't applicable for the stack, say
lint: n/aand just run tests.
Step 3 — Invoke my-code-reviewer subagent
Single Agent call, subagent_type: my-code-reviewer. Prompt:
Review the current diff in this repo against the rubric in ~/.claude/CLAUDE.md and the project's own CLAUDE.md if present. Run
git diff --no-color HEADto get the diff. Read full files for non-trivial hunks. Return your fixed-format verdict.
Pass through whatever the reviewer returns verbatim.
Step 4 — Branch on verdict
APPROVE→ continue to Step 5.REQUEST CHANGES→ print the reviewer's Blockers section and stop. Do NOT draft a commit message. The user must address Blockers and rerun.NEEDS DISCUSSION→ print the reviewer's full output and stop. Ask the user one specific question that would unblock the call.
Step 5 — Draft a commit message (do NOT commit)
Read the diff plus recent commit history (git log --oneline -10) to match the repo's style. Draft a Conventional Commits message:
<type>(<scope>): <imperative summary, ≤ 70 chars>
<body — 1–3 short paragraphs, focuses on *why*, not *what*. Wrap at 72.>
Types: feat / fix / refactor / docs / test / chore / perf. Pick the one that matches the largest portion of the diff. Scope is the top-level module or directory touched, lowercase, optional.
Show the user:
The reviewer's verdict block (verbatim).
The drafted commit message in a fenced block.
The exact command to run to commit it, e.g.:
git commit -m "$(cat <<'EOF' <message body> EOF )"
End with the literal sentence: Run the command above to commit, or edit the message first. ship-it does not commit for you.
Hard rules
- Never run
git commit,git push,git tag, or any mutating git command. This skill stops at "drafted message ready." - Never run
--no-verify. If a hook is failing, surface it; don't bypass. - Run lint + test in parallel in Step 2. Sequential wastes 30–60 seconds per invocation.
- One subagent call in Step 3. Don't spawn the reviewer twice.
- Stop fast on failure. If lint or tests fail, do not continue to review — fix-then-rerun is cheaper than reviewing broken code.
Edge cases
- Untracked files in the diff: include them in the review (
git diff --no-color HEADwon't show them, so also rungit status --porcelainand read each untracked file). - Mixed staged/unstaged: review everything (staged + unstaged) — what gets committed is the user's choice, and they need to see both.
- Submodules / monorepos: detect tooling in the current working directory, not the repo root, if a
package.json/pyproject.tomlis closer. - No tests at all: if Step 1 found a test runner but the project has zero tests, note it as a Smell in the verdict but do not block. Suggest
my-test-writeragent.