Overview
Post-merge deployment and monitoring skill. Picks up where /ship leaves off: merging the PR, verifying the deployment succeeds, and monitoring production health afterward.
When to Use
Run land once /ship pr produced a green, approved PR, and canary right after a deploy lands, whether this session merged it or not.
Subcommand Routing
| Invocation |
Action |
/deploy or /deploy land |
Merge PR and verify deployment (default) |
/deploy canary |
Post-deploy monitoring for errors and regressions |
If no subcommand is given, default to land.
Process
- Route the invocation per Subcommand Routing.
- For
land, run its Steps in order: identify, pre-merge checks, merge, wait for the deploy, health check, switch to local main.
- For
canary, run its Steps: baseline, monitor loop, per-interval report, final report, rollback suggestion on issues.
- End with the Output block for
land or the Canary Report for canary.
land
Merge a PR, wait for the deployment pipeline, and verify production health.
When to use
- After
/ship pr created a PR and CI is green.
- When a PR is approved and ready to merge.
Arguments
- No arguments: detect the PR for the current branch.
- PR number or URL: target a specific PR.
--squash: squash merge (default).
--merge: create a merge commit instead.
--no-delete: keep the branch after merge.
Steps
Identify the PR. If no argument, find the PR for the current branch:
GH_TOKEN=$(gh auth token --user <account>) gh pr view --json number,state,reviewDecision,statusCheckRollup
If no gh is available, try glab. Prefix with the appropriate token per standards/github-accounts.md or standards/gitlab-accounts.md.
Pre-merge checks. Verify all conditions are met:
| Condition |
How to check |
Blocker? |
| CI is green |
statusCheckRollup all passing |
Yes |
| PR is approved |
reviewDecision is APPROVED |
Yes |
| No merge conflicts |
mergeable is true |
Yes |
| Branch is up to date |
Compare with base branch HEAD |
Warning only |
If any blocker condition fails, stop and report the issue. Do not merge.
Merge the PR. Default to squash merge:
GH_TOKEN=$(gh auth token --user <account>) gh pr merge <number> --squash --delete-branch
If --no-delete is passed, omit --delete-branch.
If this is a dual-base PR, same change targeting two branches, omit --delete-branch per ../../rules/git-workflow.md.
Wait for deployment. Detect the deployment mechanism:
| Signal |
Platform |
How to monitor |
.github/workflows/ with deploy job |
GitHub Actions |
GH_TOKEN=$(gh auth token --user <account>) gh run list --branch main --limit 1 --json databaseId,status, then poll a one-shot GH_TOKEN=$(gh auth token --user <account>) gh run view <id> --json status,conclusion every 60 seconds, at most 20 times, and every 3 minutes while the run is queued; GitLab: glab ci status -F json on the same schedule |
| Vercel project |
Vercel |
Check Vercel MCP or vercel ls --limit 1 |
| Railway, Render, Fly |
PaaS |
Suggest user check the dashboard |
| Manual deploy |
Any |
Ask user to trigger and confirm |
If no deployment mechanism is detected, ask the user how deployments work.
Verify production health. After deployment completes:
- If a health endpoint is known, from project docs or user input,
curl it and verify 200.
- If the project has a public URL, verify it loads.
- Check for new error reports if monitoring is configured, such as through the Sentry MCP.
- Report the deployment result.
Switch to local main. After successful deployment:
git checkout main && git pull origin main
Output
## Deployment Summary
**PR:** #<number> - <title>
**Merged:** <timestamp GMT>
**Method:** squash / merge commit
**Branch deleted:** yes / no
### Deployment
**Platform:** <detected platform>
**Status:** success / pending / failed
**URL:** <production URL if known>
### Health Check
**Endpoint:** <URL checked>
**Status:** <HTTP status code>
**Errors:** none / <error details>
canary
Monitor a recently deployed change for errors, performance regressions, and unexpected behavior.
When to use
- Immediately after
/deploy land succeeds.
- When a deploy happened outside this session and the user wants a health check.
- When monitoring a risky change in the first minutes after deployment.
Arguments
- No arguments: monitor for 5 minutes with checks every 60 seconds.
--duration <minutes>: monitor for a custom duration.
--url <url>: target a specific URL for health checks.
--baseline: capture current metrics as the baseline before a deploy, run this first.
Steps
Establish baseline. If --baseline was passed or no prior baseline exists:
- Record current error rate from monitoring tools, if accessible.
- Record response time for key endpoints.
- Save as the comparison point.
Monitor loop. For each check interval:
- Verify the health endpoint returns 200.
- Check for new errors in monitoring tools, Sentry MCP if available.
- Compare current response time against baseline.
- Check browser console for JavaScript errors, if Playwright MCP is available and a frontend URL is known.
Report per interval:
| Check |
Status |
| Health endpoint |
200 OK / |
| New errors |
0 / |
| Response time |
vs |
| Console errors |
0 / |
Final report after monitoring completes:
## Canary Report
**Duration:** <N> minutes
**Intervals:** <count>
**URL:** <monitored URL>
### Health
**Uptime:** <percentage>
**Errors detected:** <count>
### Performance
**Response time (baseline):** <value>
**Response time (current):** <value>
**Delta:** <percentage change>
### Verdict
<CLEAN: no issues detected / WARNING: <issues found>>
If issues detected: suggest rollback steps:
git revert <merge-commit> && git push
- Or revert via the platform's rollback mechanism.
Rules
- Never merge a PR with failing CI checks. No exceptions.
- Never merge without approval unless the user explicitly requests it.
- Prefix every
gh or glab command with the appropriate token per standards/github-accounts.md or standards/gitlab-accounts.md.
- All timestamps in GMT.
- Canary monitoring is non-blocking: report findings, do not auto-rollback without user confirmation.
- If rate limits are a concern for monitoring, use one-shot checks instead of continuous polling per
../../rules/git-workflow.md.
- Never access production databases or infrastructure directly. Use health endpoints and monitoring tool APIs only.
Common Rationalizations
- "
statusCheckRollup is green, so CI passed": the rollup reads success when only an unrelated check ran. Confirm the CI workflows ran on the head commit with GH_TOKEN=$(gh auth token --user <account>) gh run list --commit <full-sha>.
- "The reviewer is away and the change is small": merging without approval needs the user's explicit request. Ask.
- "The canary showed errors, revert now to be safe": canary is non-blocking. Report the findings and the rollback steps, then wait for confirmation.
- "The dashboard is faster than the health endpoint": production databases and infrastructure stay off limits. Use health endpoints and monitoring APIs.
- "Delete the branch, it merged": a dual-base PR still needs its branch for the second merge. Omit
--delete-branch.
Red Flags
- Stop and report when any pre-merge blocker row fails, and leave the PR unmerged.
- Stop and ask how deployments work when no row of the deployment detection table matches.
- Stop and present the rollback steps when the health endpoint returns anything other than 200 after the deploy.
- Stop and switch to one-shot
GH_TOKEN=$(gh auth token --user <account>) gh run view checks when GH_TOKEN=$(gh auth token --user <account>) gh api rate_limit shows fewer than 500 remaining.
Verification
GH_TOKEN=$(gh auth token --user <account>) gh pr view <number> --json state returns MERGED after land.
- The deploy run for the merge commit shows
completed with conclusion success, or the user confirmed a manual deploy.
- The health endpoint returned 200, with the URL and status in the Deployment Summary.
git branch --show-current prints main and git status reports the branch up to date with origin/main.
- After
canary, the Canary Report carries a CLEAN or WARNING verdict with the interval count.
Related skills
/ship pr -- Create the PR that this skill merges.
/ship checks -- Diagnose CI failures before merging.
/incident -- Document the incident if the deploy causes problems.
/investigate -- Debug issues found during canary monitoring.
1---2name: deploy3description: Merge a shipped PR, verify the deployment, and monitor post-deploy health, with land and canary subcommands.4disable-model-invocation: true5argument-hint: "/deploy [land|canary] [pr-number]"6allowed-tools: "Read, Bash, Grep, AskUserQuestion"7sensitive: true8metadata:9 source: https://skillmd.com/skills/gufranco/deploy10---1112## Overview1314Post-merge deployment and monitoring skill. Picks up where `/ship` leaves off: merging the PR, verifying the deployment succeeds, and monitoring production health afterward.1516## When to Use1718Run `land` once `/ship pr` produced a green, approved PR, and `canary` right after a deploy lands, whether this session merged it or not.1920### Subcommand Routing2122| Invocation | Action |23|-----------|--------|24| `/deploy` or `/deploy land` | Merge PR and verify deployment (default) |25| `/deploy canary` | Post-deploy monitoring for errors and regressions |2627If no subcommand is given, default to `land`.2829## Process30311. Route the invocation per Subcommand Routing.322. For `land`, run its Steps in order: identify, pre-merge checks, merge, wait for the deploy, health check, switch to local main.333. For `canary`, run its Steps: baseline, monitor loop, per-interval report, final report, rollback suggestion on issues.344. End with the Output block for `land` or the Canary Report for `canary`.3536---3738## land3940Merge a PR, wait for the deployment pipeline, and verify production health.4142### When to use4344- After `/ship pr` created a PR and CI is green.45- When a PR is approved and ready to merge.4647### Arguments4849- No arguments: detect the PR for the current branch.50- PR number or URL: target a specific PR.51- `--squash`: squash merge (default).52- `--merge`: create a merge commit instead.53- `--no-delete`: keep the branch after merge.5455### Steps56571. **Identify the PR.** If no argument, find the PR for the current branch:58 ```59 GH_TOKEN=$(gh auth token --user <account>) gh pr view --json number,state,reviewDecision,statusCheckRollup60 ```61 If no `gh` is available, try `glab`. Prefix with the appropriate token per [`standards/github-accounts.md`](../../standards/github-accounts.md) or [`standards/gitlab-accounts.md`](../../standards/gitlab-accounts.md).62632. **Pre-merge checks.** Verify all conditions are met:6465 | Condition | How to check | Blocker? |66 |-----------|-------------|----------|67 | CI is green | `statusCheckRollup` all passing | Yes |68 | PR is approved | `reviewDecision` is APPROVED | Yes |69 | No merge conflicts | `mergeable` is true | Yes |70 | Branch is up to date | Compare with base branch HEAD | Warning only |7172 If any blocker condition fails, stop and report the issue. Do not merge.73743. **Merge the PR.** Default to squash merge:75 ```76 GH_TOKEN=$(gh auth token --user <account>) gh pr merge <number> --squash --delete-branch77 ```78 If `--no-delete` is passed, omit `--delete-branch`.79 If this is a dual-base PR, same change targeting two branches, omit `--delete-branch` per [`../../rules/git-workflow.md`](../../rules/git-workflow.md).80814. **Wait for deployment.** Detect the deployment mechanism:8283 | Signal | Platform | How to monitor |84 |--------|---------|---------------|85 | [`.github/workflows/`](../../.github/workflows) with deploy job | GitHub Actions | `GH_TOKEN=$(gh auth token --user <account>) gh run list --branch main --limit 1 --json databaseId,status`, then poll a one-shot `GH_TOKEN=$(gh auth token --user <account>) gh run view <id> --json status,conclusion` every 60 seconds, at most 20 times, and every 3 minutes while the run is `queued`; GitLab: `glab ci status -F json` on the same schedule |86 | Vercel project | Vercel | Check Vercel MCP or `vercel ls --limit 1` |87 | Railway, Render, Fly | PaaS | Suggest user check the dashboard |88 | Manual deploy | Any | Ask user to trigger and confirm |8990 If no deployment mechanism is detected, ask the user how deployments work.91925. **Verify production health.** After deployment completes:93 - If a health endpoint is known, from project docs or user input, `curl` it and verify 200.94 - If the project has a public URL, verify it loads.95 - Check for new error reports if monitoring is configured, such as through the Sentry MCP.96 - Report the deployment result.97986. **Switch to local main.** After successful deployment:99 ```100 git checkout main && git pull origin main101 ```102103### Output104105```106## Deployment Summary107108**PR:** #<number> - <title>109**Merged:** <timestamp GMT>110**Method:** squash / merge commit111**Branch deleted:** yes / no112113### Deployment114**Platform:** <detected platform>115**Status:** success / pending / failed116**URL:** <production URL if known>117118### Health Check119**Endpoint:** <URL checked>120**Status:** <HTTP status code>121**Errors:** none / <error details>122```123124---125126## canary127128Monitor a recently deployed change for errors, performance regressions, and unexpected behavior.129130### When to use131132- Immediately after `/deploy land` succeeds.133- When a deploy happened outside this session and the user wants a health check.134- When monitoring a risky change in the first minutes after deployment.135136### Arguments137138- No arguments: monitor for 5 minutes with checks every 60 seconds.139- `--duration <minutes>`: monitor for a custom duration.140- `--url <url>`: target a specific URL for health checks.141- `--baseline`: capture current metrics as the baseline before a deploy, run this first.142143### Steps1441451. **Establish baseline.** If `--baseline` was passed or no prior baseline exists:146 - Record current error rate from monitoring tools, if accessible.147 - Record response time for key endpoints.148 - Save as the comparison point.1491502. **Monitor loop.** For each check interval:151 - Verify the health endpoint returns 200.152 - Check for new errors in monitoring tools, Sentry MCP if available.153 - Compare current response time against baseline.154 - Check browser console for JavaScript errors, if Playwright MCP is available and a frontend URL is known.1551563. **Report per interval:**157158 | Check | Status |159 |-------|--------|160 | Health endpoint | 200 OK / <error> |161 | New errors | 0 / <count and summary> |162 | Response time | <current> vs <baseline> |163 | Console errors | 0 / <count> |1641654. **Final report after monitoring completes:**166167 ```168 ## Canary Report169170 **Duration:** <N> minutes171 **Intervals:** <count>172 **URL:** <monitored URL>173174 ### Health175 **Uptime:** <percentage>176 **Errors detected:** <count>177178 ### Performance179 **Response time (baseline):** <value>180 **Response time (current):** <value>181 **Delta:** <percentage change>182183 ### Verdict184 <CLEAN: no issues detected / WARNING: <issues found>>185 ```1861875. **If issues detected:** suggest rollback steps:188 - `git revert <merge-commit> && git push`189 - Or revert via the platform's rollback mechanism.190191## Rules192193- Never merge a PR with failing CI checks. No exceptions.194- Never merge without approval unless the user explicitly requests it.195- Prefix every `gh` or `glab` command with the appropriate token per [`standards/github-accounts.md`](../../standards/github-accounts.md) or [`standards/gitlab-accounts.md`](../../standards/gitlab-accounts.md).196- All timestamps in GMT.197- Canary monitoring is non-blocking: report findings, do not auto-rollback without user confirmation.198- If rate limits are a concern for monitoring, use one-shot checks instead of continuous polling per [`../../rules/git-workflow.md`](../../rules/git-workflow.md).199- Never access production databases or infrastructure directly. Use health endpoints and monitoring tool APIs only.200201## Common Rationalizations202203- "`statusCheckRollup` is green, so CI passed": the rollup reads success when only an unrelated check ran. Confirm the CI workflows ran on the head commit with `GH_TOKEN=$(gh auth token --user <account>) gh run list --commit <full-sha>`.204- "The reviewer is away and the change is small": merging without approval needs the user's explicit request. Ask.205- "The canary showed errors, revert now to be safe": canary is non-blocking. Report the findings and the rollback steps, then wait for confirmation.206- "The dashboard is faster than the health endpoint": production databases and infrastructure stay off limits. Use health endpoints and monitoring APIs.207- "Delete the branch, it merged": a dual-base PR still needs its branch for the second merge. Omit `--delete-branch`.208209## Red Flags210211- Stop and report when any pre-merge blocker row fails, and leave the PR unmerged.212- Stop and ask how deployments work when no row of the deployment detection table matches.213- Stop and present the rollback steps when the health endpoint returns anything other than 200 after the deploy.214- Stop and switch to one-shot `GH_TOKEN=$(gh auth token --user <account>) gh run view` checks when `GH_TOKEN=$(gh auth token --user <account>) gh api rate_limit` shows fewer than 500 remaining.215216## Verification217218- `GH_TOKEN=$(gh auth token --user <account>) gh pr view <number> --json state` returns `MERGED` after `land`.219- The deploy run for the merge commit shows `completed` with conclusion `success`, or the user confirmed a manual deploy.220- The health endpoint returned 200, with the URL and status in the Deployment Summary.221- `git branch --show-current` prints `main` and `git status` reports the branch up to date with `origin/main`.222- After `canary`, the Canary Report carries a CLEAN or WARNING verdict with the interval count.223224## Related skills225226- `/ship pr` -- Create the PR that this skill merges.227- `/ship checks` -- Diagnose CI failures before merging.228- `/incident` -- Document the incident if the deploy causes problems.229- `/investigate` -- Debug issues found during canary monitoring.