ship-to-production
Commit, push to main, wait for the Cloudflare deploy, and PROVE the change is live on sahin.io (deploy SHA + change marker + production screenshot). Use whenever the owner approves a change ("ship it", "deploy", "looks good", "amazing", "yes"), and as the last step of every finished change while auto-ship mode is on (see CLAUDE.md). Never report a change as done before this has confirmed it in production.
- Source file
.claude/skills/ship-to-production/SKILL.md
Ship to production and prove it
Auto-ship mode is ON for this repo (CLAUDE.md). Once the owner has approved a change, do not ask "should I commit and push?" — run this whole loop and report the result. The owner should never have to ask whether something is deployed.
1. Gate (stop and report if any fail)
npx tsx scripts/gate.ts --full # the deploy-gate skill: types, all tests, static build, SEO, bundles, worker
For UI changes the ui-before-after screenshots must already have been shown.
2. Commit only what belongs to this change
git fetch originfirst; Manus and other sessions push to main. IfHEAD..origin/mainis non-empty, rebase onto it and re-run the gate.- Other Claude sessions work in this same checkout.
git statuswill show files you did not touch: nevergit add -A. Stage your files by name. If the owner asked to ship everything, check the others pass the gate too and say whose work they are. - Never commit
.claude/launch.json(local),dist/,.wrangler/. - Message: what changed and why, ending with the attribution line from the system reminder.
3. Push and confirm
git push origin main
npx tsx scripts/confirm-production.ts --expect "<path>::<marker>" [--expect ...]
confirm-production.ts waits for the "Deploy to Cloudflare Pages" run for
HEAD, prints each job, polls until <meta name="x-deploy-sha"> on
sahin.io equals HEAD, then checks each marker on the live page (HTML, or the
JS bundles it loads for React changes). Pick markers unique to the change: a
new class, id, heading, or string. It exits 1 with the reason on any failure.
The red "Create Cloudflare Pages project (if not exists)" annotation is expected (the project exists) and does not fail the run.
4. Look at production
npx tsx scripts/ui-compare.ts --production-only --out <scratchpad>/prod --path "<changed path>#<anchor>"
Read every PNG. This step is required, not optional: on 2026-10-08 it caught the new sidebar covering the home page's company list, which all checks had passed. If production looks wrong, fix it, and run this loop again.
5. Report
Send the production PNGs with SendUserFile, then reply with:
- the commit SHA and subject, and the deploy run link
- the
confirm-production.tsresult (deploy SHA live + markers found) - anything shipped that was not yours, or anything left uncommitted and why
If any step failed, say so plainly with the output. Never write "deployed"
or "live" without a passing confirm-production.ts run.