skills/ship/SKILL.md
--- name: ship description: Ship a feature branch the local-CI-first way — run the full local gate, push, open a PR, squash-merge, then deploy, without waiting on GitHub Actions. Use when a branch is ready for main and you want it merged and deployed now. Reads CI policy from `ro ci` (default skips remote CI because GitHub Actions billing keeps hitting limits). Sibling to /ro:gh-ship (waits on GitHub checks) and /ro:cf-ship (the deploy half). Triggers on "ship it", "ship this", "merge and deploy
npx skillsauth add RonanCodes/ronan-skills skills/shipInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The premise: GitHub Actions billing keeps hitting spending limits, so waiting on remote CI stalls every merge. We don't want to wait on it. Instead the local git hooks are the real gate (pre-commit formats, pre-push runs the full local CI), and once the local gate is green we open the PR and squash-merge straight away, then deploy. GitHub still records the PR; it just isn't the gate.
This is the default. A project can opt back into waiting on remote CI by setting
remoteCI: "require" (see Policy below), in which case this skill behaves
like /ro:gh-ship.
main. Always a feature branch → PR → squash-merge.main.autoDeploy: false or --no-deploy).main,
with no remote CI test job at all (no pull_request trigger, no needs: test). Don't just bypass a remote CI job with --admin, delete it: the pre-push
hook already ran the suite, so a remote re-run only burns Actions minutes. Full
rule + workflow shape: canon/ci-cd-policy.md.Read it, don't hardcode it:
ro ci show # full resolved policy
ro ci get remoteCI # "skip" | "require"
ro ci get mergeOnLocalPass # bool
ro ci get autoDeploy # bool
Resolution order (later wins): built-in default → ~/.claude/ci-policy.json
(global) → .ro-ci.json (committed, repo-declared) → .ro-ci.local.json
(gitignored, personal override). Set the global once with ro ci init then edit.
--require-remote-ci forces remoteCI=require for this run; --no-deploy
forces autoDeploy=false.
1. Guard: refuse if on main/master. If on main, stop and tell the user to branch.
2. Ensure work is committed (defer to /ro:commit for message + timestamp rules).
3. Run the local gate explicitly so failures surface here, not just in the hook:
pnpm quality-checks (or the repo's equivalent; see "Local gate" below)
If it fails, stop. Do not push.
4. Push the branch (the pre-push hook re-runs the gate — that's fine, it's fast).
5. Open the PR: gh pr create --base main --fill (or --title from arg)
6. Merge, per policy:
remoteCI == "skip" and mergeOnLocalPass:
gh pr merge --squash --admin --delete-branch
(--admin bypasses the billing-blocked / unstarted remote checks)
remoteCI == "require":
watch checks, merge on green — hand off to /ro:gh-ship behaviour.
7. Deploy, if autoDeploy and not --no-deploy:
defer to the repo's deploy path — /ro:cf-ship (Cloudflare),
/ro:fly-deploy (Fly), or `pnpm deploy`. Skip for non-deployable repos
(skills, wiki) — those have no deploy step.
DB gate: if the repo has a drizzle/ directory, the deploy path MUST
apply pending migrations to prod AND assert the prod DB has the
code-expected schema before serving the new code, failing loudly on
drift. /ro:cf-ship and /ro:fly-deploy carry this gate; a bare
`pnpm deploy` must run it too. Canon: canon/db-deploy-gate.md.
8. Sync local main: git checkout main && git pull --ff-only
If --admin is refused (not an admin on the repo), fall back to: report that the
merge needs either admin rights or remote CI, and ask the user how to proceed.
The gate is whatever the repo's pre-push hook runs. For the standard pnpm repo
that's the quality-checks script:
prettier --check . && eslint && astro check && astro build && vitest run
Plus Playwright e2e where it stays fast. Perf budget: the whole gate should finish in a couple of minutes. If it creeps past ~3–4 min, investigate and trim (Docker-in-the-loop and slow full-browser matrices are the usual culprits) rather than living with a gate nobody waits for. A gate that's too slow gets skipped, which defeats the point.
Apply this set to any repo following the policy (see /ro:git-guardrails for the guard details):
| Hook | Runs | Why |
|---|---|---|
| pre-commit | lint-staged (prettier --write on staged) | never commit unformatted code |
| commit-msg | commitlint --edit "$1" | enforce emoji-conventional commits |
| pre-push | full local CI + refuse pushes to main | the real gate; protect main |
The pre-push main-guard:
while read -r _ _ remote_ref _; do
case "$remote_ref" in refs/heads/main|refs/heads/master)
echo "✋ Direct push to main is not allowed. Open a PR and squash-merge." >&2
exit 1 ;;
esac
done
Belt-and-braces: also set GitHub branch protection requiring a PR
(gh api -X PUT repos/{owner}/{repo}/branches/main/protection ...) so main is
protected even when hooks aren't installed. Caveat: branch protection needs
GitHub Pro for private repos (free returns "Upgrade to GitHub Pro or make this
repository public"). For private repos on the free plan, the pre-push main-guard
is the only enforcement — make sure the hook is installed.
testing
--- name: linear-pipeline description: The Fable orchestrator for a single dispatched Linear ticket. Holds almost no context itself; it receives `--issue <ID> --detached`, decides the stage sequence, and fans out a sub-agent per stage, passing forward only each stage's artifact (never re-derived, never inlined into its own context). Step zero, before any planning or stage routing, is a boundary triage against `canon/security-boundary.md` (#199): a match tags Ronan Connolly and stops the run, no
development
--- name: in-your-face description: Capture a chat-only answer into a durable artifact (markdown + HTML, PDF when cheap) and launch it automatically so the user cannot miss it. Use when user says "in your face", "don't let me lose this", "save that answer", "make that durable", or right after answering a substantive side question (a recipe, comparison, how-to, or generated prompt) that would otherwise die with the context. category: workflow argument-hint: [--no-open] [--vault <short>] [hint of
tools
One-shot headless OpenAI Codex CLI calls for background/admin AI tasks — summaries, classification, extraction, admin glue. The default engine for anything that runs AI constantly in the background (daemon-driven, per-event), because it bills the flat ChatGPT subscription instead of Claude usage or per-token API spend, and it keeps working while Claude is rate-limited. NEVER for coding — coding stays Claude. Use when a skill or daemon needs a cheap always-on AI call, when the user says "use codex", "ask codex", "codex as backup", or when building a background summarizer/classifier into a listener or loop. Reads auth from ~/.codex/auth.json (ChatGPT account, no API key).
research
Turn a warranty rejection, repair quote, or RMA email into a cited decision brief — legal read (NL/EU consumer law), is the part user-serviceable, live part and new-unit prices, repair-vs-DIY-vs-new economics, before-you-send-it checklist, deadlines. Use when the user pastes or screenshots a repair quote, warranty rejection, "not covered" email, onderzoekskosten fee, or asks "should I repair or replace this".