--- name: ship description: Push, open a PR, and watch CI; land mode merges and cleans branches. Triggers "ship it", "create PR", "babysit CI", "land it", "fix CI and merge". context: fork --- # Ship Pipeline ## Standalone Codex Skip Claude's `!command` interpolation below. Run `git branch --show-current`, `git status --porcelain`, and `git log --oneline -5` explicitly. Create a new reviewer with `spawn_agent`, continue it while live with `send_message`, trigger another turn once it is idle with `followup_task`, wait with `wait_agent`, and stop its current turn with `interrupt_agent` only when necessary. Never spawn `codex-verifier` and never run `codex-run.ts` from inside Codex. Writers share the working tree unless the live host explicitly offers isolation. Assign non-overlapping ownership and serialize any implementer and test-writer fixes; only read-only reviewers may overlap. Codex implementers are not promised Claude worktree isolation. Codex also skips TLDR and uses `git diff --name-only`, direct import searches, and test-name searches to choose affected tests. You are in **Maestro orchestration mode**. Execute the shipping checklist in order. ## Claude current state - Branch: !`git branch --show-current 2>/dev/null || echo "unknown"` - Working tree: !`git status --porcelain 2>/dev/null | head -20` - Recent commits: !`git log --oneline -5 2>/dev/null || echo "no commits"` ## Pipeline (All Steps Mandatory) ### Step 0: Preflight ```bash ssh-add -l ``` If no identities loaded: **Unlock 1Password and retry — git signing will fail otherwise.** Agent drops mid-flow are a recurring cause of failed pushes; catch it now, not after the commit. Read and validate `package.json` before choosing commands. Invalid JSON or invalid script declarations block the pipeline. Do not commit until all applicable gates in Steps 1–4 (typecheck/build/test/lint) are green; record an absent build script as N/A with its reason. Skipping ahead is where amend churn comes from — `--amend` to fix a lint error you would have caught in 30 seconds invalidates signatures and CI runs. ### Step 1: Type Check ```bash bunx tsc --noEmit ``` If errors: fix them. Do not proceed until clean. ### Step 2: Build Inspect the validated manifest: if `scripts.build` is a nonempty string, run: ```bash bun run build ``` If the configured build fails, fix it; do not proceed until clean. If `build` is absent, record **N/A — no build script** and continue with the applicable typecheck, test, and lint gates. An empty, whitespace-only, or non-string build declaration is invalid and blocks the pipeline. Do not add a dummy build script or silently replace a failing build with typecheck. A proof runner that only detects typecheck/test/lint does not replace this configured-build gate. ### Step 3: Test (if tests exist) **3a. Affected tests first.** In Claude, use TLDR when available. Standalone Codex uses the native searches in its host branch. Run only the tests touched by your changes before the full suite. ```bash tldr change-impact --project . 2>/dev/null ``` If TLDR returns a list, run those tests first (`bun test ` or `vitest run `). If they fail, fix before the full run — don't waste cycles on the rest. **3b. Full suite.** Select one configured runner before executing it. Never treat a second runner as a fallback after a real test failure: ```bash if bun -e 'const p = await Bun.file("package.json").json(); process.exit(typeof p.scripts?.test === "string" ? 0 : 1)'; then bun run test elif bun -e 'const p = await Bun.file("package.json").json(); process.exit(p.devDependencies?.vitest || p.dependencies?.vitest ? 0 : 1)'; then ./node_modules/.bin/vitest run else bun test fi ``` If no tests or runner are configured, record the evidence and skip this step. If the selected runner fails, stop and fix that failure. Do not run a narrower suite to turn a real failure green. ### Step 4: Lint ```bash biome check . ``` If errors: fix or justify. ### Step 5: Web Quality Gate Quick sanity check before review: - [ ] No `loading="lazy"` on above-fold/LCP images - [ ] Images have explicit dimensions or `fill` prop - [ ] No `console.log` left in production code - [ ] Meta tags present on new pages (`title`, `description`, `canonical`) - [ ] Structured data valid on new content pages If issues found: fix them before proceeding to review. ### Step 6: Review Changes Spawn `reviewer` agent: ``` Agent(reviewer, "Review all staged changes for quality, TypeScript strictness, a11y, and performance issues.") ``` **Standalone Codex branch:** follow the native lifecycle above and use a fresh read-only `reviewer`. Skip the Claude bridge branch below. When the Codex bridge is available, run a cross-model review **in parallel** — a different model family catches what Claude self-review misses, and this is right before a commit lands, the cheapest place to catch a Critical: ``` Agent(codex-verifier, "Cross-model review of the staged diff. Report findings by severity.") ``` If Claude and Codex disagree on a Critical/HIGH finding, surface it to the user as a gate **before** Step 7 — don't auto-commit through a cross-model disagreement. The bridge is gated and fails open: if Codex is unavailable, proceed with the Claude review alone. If the `codex-verifier` spawn fails, or it reports that Bash was stripped (forked skill contexts), run `bun "$HOME/.claude/src/scripts/codex-run.ts" review` directly instead — never skip the cross-model pass. ### Step 7: Commit (Bisectable) Analyze the diff to decide commit strategy: ```bash git diff --cached --stat | tail -1 ``` **Small diff** (<50 lines changed across <4 files): Single commit. ```bash git add git commit -m ": " ``` **Larger diff**: Split into ordered commits by dependency layer. Each commit must be independently valid — no broken imports, no forward references. **Commit order (skip layers with no changes):** 1. **Infrastructure** — config files, env changes, package.json, build config 2. **Types/interfaces** — type definitions, schemas, shared interfaces 3. **Logic** — utilities, hooks, services, lib code (group with their tests when small) 4. **UI** — components, pages, styles (group with their tests when small) 5. **Tests** — remaining test files not already grouped with their subjects 6. **Meta** — docs, changelog, version bumps — **always last commit** **Per-commit validation:** Each commit must independently pass: ```bash bunx tsc --noEmit && bunx biome check . ``` If a commit would break either check in isolation, merge it with the next commit in the sequence. **Commit messages:** Each gets a conventional prefix (`feat:`, `fix:`, `refactor:`, `test:`, `chore:`, `docs:`). ### Step 8: Push and PR ```bash git push origin HEAD gh pr list --head "$(git branch --show-current)" --state open --json number,url ``` If that list is non-empty, a PR already exists for this branch: the push updated it, so skip `gh pr create` and go to Step 9. Never open a second PR for the same branch. If `gh` is not available, provide the push command and instruct the user to create the PR manually. **Author the PR body — do NOT use `--fill`.** `--fill` dumps the commit messages into the description, which reads as technical and over-engineered. Lead with a plain-English "What this does" (see `rules/git.md` "Signal, not spam"): ```bash gh pr create --title ": " --body "$(cat <<'EOF' ## What this does <2–3 plain sentences: what changed and why it matters — the real-world effect, not the mechanism. A teammate who didn't write it should get it on one read.> ## Summary - ## Test Plan - [ ] EOF )" ``` Write "What this does" from the *diff and its purpose*, not by pasting commit subjects. If you can't explain it plainly, the change is unclear — say so, don't reach for bigger words. ### Step 9: Watch CI Until Green (post-push) After `gh pr create`, watch the PR-attached checks until all pass. Use `gh pr checks` as the source of truth — it covers all PR checks, not just GitHub Actions runs (which `gh run list` would miss). ```bash gh pr checks --json name,bucket,state,workflow,link gh pr checks --watch --fail-fast ``` If a check fails: 1. Identify the failing job and fetch logs (`gh run view RUN_ID --log-failed` for GHA; follow the `link` for external services). On a red or missing check, also fetch the team-knowledge index and read any note whose title matches the workflow/CI symptom before assuming a runner problem; the fetch command is in docs/knowledge-system.md (fail-open — skip if `gh` is unavailable). 2. **Reproduce the exact failing guard locally against the real built artifact** before pushing a fix — run the same test script / check command CI ran, against the binary or output CI would see. A fix verified only by reasoning is a push-and-pray loop. 3. Apply the smallest fix. Use the `fix` skill's "Variant: Failing PR CI" if the failure is non-trivial. For version/metadata guards, use the repo's canonical script (`bump-version.sh`-style) — never hand-edit versioned fields; hand-bumps desync the sibling fields the script maintains. 4. Push, then re-read `gh pr checks` — the check set can change between runs. 5. Repeat until green. Guardrails: - Scope each fix to a single failure cause. - If failures are flaky, retry once and report flake evidence rather than chasing a phantom fix. - If the failure is unrelated to the PR and already fixed on main, merge main into the branch instead of bloating the PR. - Never take a watcher pipeline's exit code as the verdict — in `gh run watch ID; gh run view ID ...` the shell reports the *last* command's exit, not the run's outcome. Read the conclusion explicitly: `gh run view ID --json conclusion --jq .conclusion` (or `gh pr checks`). ### Land Mode (existing PR → merged → clean) Invoked as `/ship land` or when the ask is "review/fix CI then merge then clean up" on a PR that already exists. Skip Steps 0–8; run: 1. Capture the head you're validating: `gh pr view --json headRefOid,reviewDecision,mergeable`. Everything below is checked against THIS `headRefOid`. 2. `gh pr checks` — if red, run the Step 9 CI-fix loop until green. A CI fix that pushes a new commit moves the head: re-capture `headRefOid` and re-check against it. 3. Confirm review state from step 1: if `reviewDecision` is CHANGES_REQUESTED or `mergeable` is CONFLICTING, stop and report — do not merge through either. 4. **Re-validate immediately before merging** — `gh pr view --json headRefOid,reviewDecision,mergeable`. All three can drift while the CI loop ran (a new push moves `headRefOid`; a late review flips `reviewDecision` to CHANGES_REQUESTED; a base-branch change flips `mergeable`) — the head moving is not the only race. If `headRefOid` differs from the SHA you validated, STOP and re-run checks against the new head; if `reviewDecision`/`mergeable` regressed, STOP and report. Don't merge stale-green. (A post-*merge* SHA check can't catch a moved head: a squash commit does not contain the PR head as an ancestor, so the guard has to run *before* merge. See the `gh-merge-race` learning.) 5. Merge with the repo's preferred strategy (`gh pr merge --squash --delete-branch` unless repo convention says otherwise). Branch protection / a merge queue, if enabled, is the atomic final gate. 6. Cleanup: `git checkout main && git pull`, delete the local branch, prune remotes (`git remote prune origin`). Leave only main unless other branches have open PRs. 7. Report: PR link, merge commit, branches deleted. Per the Autonomy Contract (CLAUDE-FULL.md): steps 5–7 are pre-approved once CI is green, the head is confirmed unchanged, and review is clean — report, don't ask. External-org repos: land mode is forbidden entirely. ## Rules - NEVER skip an applicable type check or configured build; an absent build script is N/A with a recorded reason - NEVER create a PR with failing tests - Conventional commit messages only (`feat:`, `fix:`, `refactor:`, etc.) - No AI attribution in commits or PR descriptions — see `rules/git.md`. - Each bisectable commit must pass `tsc --noEmit` AND `biome check` independently - If total diff is small, single commit is fine -- don't over-split ## Output Return: - **Build status**: Pass/Fail/N/A (N/A requires the reason: no build script) - **Test status**: Pass/Fail (with count) - **Lint status**: Pass/Fail - **Review status**: Approved/Needs Changes - **Commits created**: Count and summary of each - **PR link**: URL if created