Agent Skills: Candid Ship

Ship your changes - review, build, test, create PR, and optionally auto-merge

UncategorizedID: ron-myers/candid/candid-ship

Install this agent skill to your local

pnpm dlx add-skill https://github.com/ron-myers/candid/tree/HEAD/skills/candid-ship

Skill Files

Browse the full folder contents for candid-ship.

Download Skill

Loading file tree…

skills/candid-ship/SKILL.md

Skill Metadata

Name
candid-ship
Description
Ship your changes - review, build, test, create PR, and optionally auto-merge

Candid Ship

Orchestrate the full shipping workflow: review code via candid-loop, run build and tests, create a GitHub PR, and optionally auto-merge. Aborts on any failure.

Workflow

Execute these steps in order:

Step 1: Pre-Flight Checks

Verify the environment is ready for shipping.

1.1: Check gh CLI

gh auth status 2>&1

If command fails or gh not found:

Pre-flight failed: GitHub CLI (gh) is not installed or not authenticated.
Install: https://cli.github.com/
Authenticate: gh auth login

Abort.

1.2: Check Git Repository

git rev-parse --is-inside-work-tree 2>&1

If not inside a git repo: abort with Pre-flight failed: Not inside a git repository.

1.3: Check Current Branch

git branch --show-current

Store as currentBranch. If empty (detached HEAD): abort with Pre-flight failed: Detached HEAD state. Check out a branch first.

Step 2: Load Configuration

Load ship configuration from CLI flags and config files.

Precedence (highest to lowest):

  1. CLI flags
  2. Project config (.candid/config.jsonship field)
  3. User config (~/.candid/config.jsonship field)
  4. Defaults

Parse CLI Flags

| Flag | Description | Default | |------|-------------|---------| | --auto-merge | Enable auto-merge | from config | | --no-auto-merge | Disable auto-merge | from config | | --skip-review | Skip candid-loop step | false | | --skip-build | Skip build command | false | | --skip-tests | Skip test command | false | | --dry-run | Show plan without executing | false |

If both --auto-merge and --no-auto-merge are provided, --no-auto-merge wins.

Check Project Config

jq -r '.ship // null' .candid/config.json 2>/dev/null

If the ship field exists, extract:

  • buildCommand (string) — shell command for build verification
  • testCommand (string) — shell command for tests
  • targetBranch (string) — PR target branch
  • autoMerge (boolean) — auto-merge after PR creation
  • additionalPrompt (string) — extra context for candid-loop/review

Output when loading: Using ship settings from project config

Check User Config

Same procedure for ~/.candid/config.json if project config doesn't have ship field.

Output when loading: Using ship settings from user config

Resolve targetBranch Default

If targetBranch is not set by config:

  1. Check mergeTargetBranches in project config → use first entry
  2. Check mergeTargetBranches in user config → use first entry
  3. Default to "main"

Verify the target branch exists:

git rev-parse --verify [targetBranch] 2>/dev/null || git rev-parse --verify origin/[targetBranch] 2>/dev/null

If target branch doesn't exist: abort with Target branch "[targetBranch]" does not exist locally or on remote.

Apply Defaults

For any options not set:

buildCommand = null (skip build if not set)
testCommand = null (skip tests if not set)
targetBranch = resolved per above
autoMerge = false
additionalPrompt = null

Validate Current Branch != Target Branch

If currentBranch == targetBranch:

Cannot ship: you are on the target branch ([targetBranch]). Check out a feature branch first.

Abort.

Check Commits Ahead

git log --oneline [targetBranch]..HEAD 2>/dev/null | head -20

If no commits ahead: abort with No commits ahead of [targetBranch]. Nothing to ship.

Step 3: Display Plan

Show what will be executed:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Candid Ship Plan
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Branch: [currentBranch] → [targetBranch]

Steps:
  1. 🔍 Review code (candid-loop)           [or SKIP]
  2. 🔨 Build: [buildCommand]               [or SKIP — not configured]
  3. 🧪 Tests: [testCommand]                [or SKIP — not configured]
  4. 📋 Create pull request
  5. 🔀 Auto-merge: enabled                 [or disabled]

If additionalPrompt is set:

Review context: "[additionalPrompt]"

If --dry-run: Output: Dry run complete. No changes made. Exit.

If not dry-run: Use AskUserQuestion:

Question: "Proceed with this shipping plan?"

Options:

  1. "Yes, ship it"
  2. "No, cancel"

If "No, cancel": exit with Ship cancelled.

Step 4: Run Review (candid-loop)

Skip if --skip-review flag is set. Output: Skipping review (--skip-review)

Display:

Step 1/5: Running code review...

Invoke candid-loop via the Skill tool: /candid-loop

If additionalPrompt is set, include it in the skill invocation by adding this instruction before invoking:

"IMPORTANT: During this review, also consider the following additional context: [additionalPrompt]"

After candid-loop completes, check its summary output:

  • If PASS (no issues remaining): continue. Output: Review passed.
  • If INCOMPLETE (max iterations reached with remaining issues): Use AskUserQuestion:
    • Question: "Review completed with remaining issues. Continue shipping?"
    • Options:
      1. "Yes, continue anyway"
      2. "No, abort"
    • If "No, abort": exit with Ship aborted: unresolved review issues.
  • If CANCELLED: abort with Ship aborted: review was cancelled.

Step 5: Run Build

Skip if --skip-build flag is set OR buildCommand is not configured.

If skipped due to no config: Output: Skipping build (not configured) If skipped due to flag: Output: Skipping build (--skip-build)

Display:

Step 2/5: Running build...
$ [buildCommand]

Execute the build command:

[buildCommand]

If build fails (non-zero exit code):

Build failed. Ship aborted.

Show the build output so the user can diagnose. Abort.

If build succeeds:

Build passed.

Step 6: Run Tests

Skip if --skip-tests flag is set OR testCommand is not configured.

If skipped due to no config: Output: Skipping tests (not configured) If skipped due to flag: Output: Skipping tests (--skip-tests)

Display:

Step 3/5: Running tests...
$ [testCommand]

Execute the test command:

[testCommand]

If tests fail (non-zero exit code):

Tests failed. Ship aborted.

Show the test output so the user can diagnose. Abort.

If tests succeed:

Tests passed.

Step 7: Create Pull Request

Display:

Step 4/5: Creating pull request...

7.1: Generate PR Title

git log [targetBranch]..HEAD --oneline
  • Single commit: Use that commit message as the title
  • Multiple commits: Clean the branch name into a title:
    • Remove prefix (e.g., feature/, fix/, ron-myers/)
    • Replace hyphens/underscores with spaces
    • Capitalize first letter
    • Example: feature/add-auth-middlewareAdd auth middleware

Truncate title to 70 characters if needed.

7.2: Generate PR Body

git log [targetBranch]..HEAD --pretty=format:"- %s"

Assemble the body:

## Summary
[commit list from git log]

## Verification
- Review: [PASS — N iterations, M issues fixed | SKIPPED]
- Build: [PASS | SKIPPED]
- Tests: [PASS | SKIPPED]

---
*Shipped with [candid-ship](https://github.com/ron-myers/candid)*

7.3: Push Branch

Ensure the branch is pushed to remote:

git push -u origin [currentBranch]

If push fails, abort with error message.

7.4: Create PR

gh pr create --base [targetBranch] --title "[title]" --body "[body]"

Capture the PR URL from stdout. If creation fails, abort with error message.

Output: PR created: [URL]

Step 8: Auto-Merge (Optional)

Skip if autoMerge is false. Output: Auto-merge: disabled (manual merge required)

If autoMerge is true:

Display:

Step 5/5: Enabling auto-merge...
gh pr merge [PR_URL] --squash --auto

If auto-merge fails (e.g., repo doesn't have auto-merge enabled):

⚠️  Auto-merge failed: [error message]
The repository may not have auto-merge enabled in Settings → General → Pull Requests.
PR is still open at: [URL]

Do NOT abort — the PR was already created. Continue to summary.

If auto-merge succeeds:

Auto-merge enabled. PR will merge when checks pass.

Step 9: Display Summary

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Candid Ship Complete
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Review:   [PASS (N iterations, M issues fixed) | SKIPPED]
Build:    [PASS | SKIPPED]
Tests:    [PASS | SKIPPED]
PR:       [URL]
Merge:    [Auto-merge enabled | Manual merge required | Auto-merge failed]

Configuration

Config File Schema

Add to .candid/config.json:

{
  "version": 1,
  "ship": {
    "buildCommand": "npm run build",
    "testCommand": "npm test",
    "targetBranch": "stable",
    "autoMerge": false,
    "additionalPrompt": "Focus on security and ensure all API endpoints have auth middleware"
  }
}

Field Descriptions

| Field | Type | Default | Description | |-------|------|---------|-------------| | ship.buildCommand | string | null | Shell command for build verification. Skip if not set. | | ship.testCommand | string | null | Shell command for running tests. Skip if not set. | | ship.targetBranch | string | first mergeTargetBranches or "main" | Branch to target for PR. | | ship.autoMerge | boolean | false | Auto-merge PR after creation via gh pr merge --squash --auto. | | ship.additionalPrompt | string | null | Extra context passed to candid-loop/review. |

Examples

Minimal — just PR creation:

{
  "ship": {
    "targetBranch": "main"
  }
}

Full CI pipeline with auto-merge:

{
  "ship": {
    "buildCommand": "npm run build",
    "testCommand": "npm test",
    "targetBranch": "stable",
    "autoMerge": true,
    "additionalPrompt": "Ensure error handling covers all async operations"
  }
}

Python project:

{
  "ship": {
    "buildCommand": "python -m py_compile src/**/*.py",
    "testCommand": "pytest -v",
    "targetBranch": "main",
    "autoMerge": false
  }
}

CLI Examples

# Ship with all defaults from config
/candid-ship

# Force auto-merge
/candid-ship --auto-merge

# Quick ship — skip review, just build/test/PR
/candid-ship --skip-review

# See what would happen without doing it
/candid-ship --dry-run

# Skip everything except PR creation
/candid-ship --skip-review --skip-build --skip-tests

Remember

The goal of candid-ship is to automate the entire shipping workflow so you can go from code to merged PR with one command.

Fail-fast principle: Any failure (review incomplete, build fail, test fail) aborts immediately with a clear message. The only exception is auto-merge failure — the PR is already created and shouldn't be wasted.

Pre-flight checks: Always validate the environment before starting. It's frustrating to complete a full review + build + test cycle only to discover gh isn't installed.