land-and-deploy
The facts
Its description
Land and deploy workflow. (gstack) Triggers: merge and deploy; land the pr; ship to production
The description the agent reads to decide when to use it. Phrases the author says should start it.
When it starts
A person asking to merge a pull request and get it deployed to production, or to land a PR that /ship already opened. The skill picks up an existing PR, checks readiness, merges it, monitors the deploy and verifies production.
Things a person might say (the model's guesses)
- “Merge PR #412 and deploy it”
- “land the PR and watch the deploy”
- “ship this to production”
A model's summary of when it is used.
Tools it may use, or may not
allowed-tools: Bash, Read, Write, Glob, AskUserQuestion
Tools it may use while it runs without asking you first.
Runs scripts
bin/gstack-skill-start, scripts/question-registry.ts, bin/gstack-question-preference, bin/gstack-question-log, bin/gstack-paths (first 5 of 17 lines)
Scripts the text names. Found by matching words, so treat them as pointers.
Files it mentions
sections/first-run-validation.md, sections/readiness-gate.md, sections/merge-and-deploy.md, sections/canary.md
Files the text names, such as ones to read or write. Found by matching words, so treat them as pointers.
Stops for a person
7 lines stop to ask a person (first 5 linked)
Lines that stop and wait for a person before going on. Found by matching words, so treat them as pointers.
What it leads to
- hands off to benchmark when performance matters line 578
- hands off to canary for extended monitoring line 578
- hands off to document-release when docs need updating line 579
- calls setup-browser-cookies for an authenticated page without a human sign-in canary.md, line 122
- requires autoplan when reviews are stale readiness-gate.md, line 300
- requires browse before any browser step canary.md, line 32
- requires review when engineering review is stale or missing readiness-gate.md, line 96
- requires setup-deploy when deploy config is missing or the user wants fuller setup first-run-validation.md, line 186
- requires ship line 171
Other skills this one hands off to, calls, requires or offers instead, as a model read them.
What leads to it
- gstack hands off to this PROACTIVE all, or user names it gstack, line 213
Other skills that hand off to this one, call it, require it or offer it instead, as a model read them.
What leads to it
- setup-deploy hands off to this setup-deploy, line 141
Other skills that hand off to this one, call it, require it or offer it instead, found by matching their names, so treat them as pointers.
Names skills outside this collection
- design-review-lite readiness-gate.md, line 20
- codex-review readiness-gate.md, line 20
- adversarial-review readiness-gate.md, line 20
- codex-plan-review readiness-gate.md, line 21
Skills the text names that are not in this collection, as a model read them.
Licence
MIT, from LICENSE
The terms its author shares it under, which let it be shown here.
Other files in this skill (6) Close
The text
Most marks come from matching words in the file, so treat them as pointers.
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly --> <!-- Regenerate: bun run gen:skill-docs -->
Raw lines 1 to 19Boilerplate, lines 20 to 127. The same text appears in 45 other files here. Close
Step 0: Detect platform and base branch
First, detect the git hosting platform from the remote URL:
git remote get-url origin 2>/dev/null- If the URL contains "github.com" → platform is GitHub
- If the URL contains "gitlab" → platform is GitLab
- Otherwise, check CLI availability:
gh auth status 2>/dev/nullsucceeds → platform is GitHub (covers GitHub Enterprise)glab auth status 2>/dev/nullsucceeds → platform is GitLab (covers self-hosted)- Neither → unknown (use git-native commands only)
Determine which branch this PR/MR targets, or the repo's default branch if no PR/MR exists. Use the result as "the base branch" in all subsequent steps.
If GitHub:
gh pr view --json baseRefName -q .baseRefName— if succeeds, use itgh repo view --json defaultBranchRef -q .defaultBranchRef.name— if succeeds, use it
If GitLab:
glab mr view -F json 2>/dev/nulland extract thetarget_branchfield — if succeeds, use itglab repo view -F json 2>/dev/nulland extract thedefault_branchfield — if succeeds, use it
Git-native fallback (if unknown platform, or CLI commands fail):
git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||'- If that fails:
git rev-parse --verify origin/main 2>/dev/null→ usemain - If that fails:
git rev-parse --verify origin/master 2>/dev/null→ usemaster
If all fail, fall back to main.
Print the detected base branch name. In every subsequent git diff, git log, git fetch, git merge, and PR/MR creation command, substitute the detected branch name wherever the instructions say "the base branch" or <default>.
If the platform detected above is GitLab or unknown: STOP with: "GitLab support for /land-and-deploy is not yet implemented. Run /ship to create the MR, then merge manually via the GitLab web UI." Do not proceed.
/land-and-deploy — Merge, Deploy, Verify
As Release Engineer, pick up the PR created by /ship: check readiness, merge with approval, monitor deployment, verify production, and report evidence.
Boilerplate, lines 174 to 176. The same text appears in 3 other files here. Close
Arguments
/land-and-deploy— auto-detect PR from current branch, no post-deploy URL/land-and-deploy <url>— auto-detect PR, verify deploy at this URL/land-and-deploy #123— specific PR number/land-and-deploy #123 <url>— specific PR + verification URL
Automation and approval
Automate read-only detection and polling. First-run setup confirmation (Step 1.5) and pre-merge approval (Step 3.5) are mandatory when applicable. Stop on missing access, unknown target/state, unapproved red, pending or missing CI, conflicts, or failing tests. After any merge error, read server state before deciding whether to stop. Failures, timeouts, staging choices, rollback, and optional cleanup use the explicit decisions below; no approval overrides a blocker or authorizes a different revision.
Raw lines 183 to 191Voice & Tone
Narrate progress, name the actual app/PR and explain the stakes before asking. First run: teach what each check does. Confirmed runs: brief status updates.
Raw lines 192 to 198
Section index — Read each section when its situation applies
This skill is a decision-tree skeleton. The steps below point to on-demand sections. Read a section in full before doing its step; do not work from memory.
| When | Read this section |
|---|---|
| running the first-run dry-run validation — Step 1.5's check returned FIRST_RUN or CONFIG_CHANGED (skip on CONFIRMED) | sections/first-run-validation.md |
| the pre-merge readiness gate (Step 3.5) — the last check before the irreversible merge | sections/readiness-gate.md |
| merging the PR and detecting the deploy strategy (Steps 4-5) | sections/merge-and-deploy.md |
| Step 7's URL health check, or any browser step or third-party site action (vendor dashboard, API key, webhook) | sections/canary.md |
Raw lines 199 to 212
Step 1: Pre-flight
Tell the user: "Checking access and finding your PR."
- Check GitHub CLI authentication:
gh auth statusIf unauthenticated, STOP; ask the user to run gh auth login, then retry.
- Save any URL as
VERIFY_URL(an explicit verification request). SetPR_NUMBER
to the numeric #NNN argument, or detect it once from the current branch:
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) || exit 1
if [ -z "$PR_NUMBER" ]; then
PR_NUMBER=$(gh pr view --repo "$REPO" --json number -q .number) || exit 1
fi
PR_JSON=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json number,state,title,url,mergeable,baseRefName,headRefName,headRefOid,baseRefOid) || exit 1
PR_HEAD=$(printf '%s' "$PR_JSON" | jq -er .headRefOid) || exit 1
HEAD_BRANCH=$(printf '%s' "$PR_JSON" | jq -er .headRefName) || exit 1
BASE_BRANCH=$(printf '%s' "$PR_JSON" | jq -er .baseRefName) || exit 1Carry these values across fresh shells. Every later command targets this repository and PR, never implicit current-branch detection. A failed query is unknown, not an empty PR. Tell the user the selected number, title, head → base and head SHA.
- No PR: STOP, suggest
/ship. CLOSED: STOP, ask to reopen it. MERGED:
STOP, suggest /canary <url>; do not merge again or claim a deploy happened. Only OPEN continues. Before any HEAD-based evidence, require the matching clean checkout:
LOCAL_HEAD=$(git rev-parse HEAD) || exit 1
LOCAL_BRANCH=$(git branch --show-current) || exit 1
LOCAL_STATUS=$(git status --porcelain) || exit 1
if [ "$LOCAL_HEAD" != "$PR_HEAD" ] || [ "$LOCAL_BRANCH" != "$HEAD_BRANCH" ] || [ -n "$LOCAL_STATUS" ]; then
echo "LOCAL_TARGET_MISMATCH"
exit 1
fi
git fetch "https://github.com/$REPO.git" "$BASE_BRANCH" || exit 1
BASE_SHA=$(git rev-parse FETCH_HEAD) || exit 1
SCOPE_RESULT=$(~/.claude/skills/gstack/bin/gstack-diff-scope "$BASE_SHA") || exit 1
eval "$SCOPE_RESULT"On mismatch, STOP and ask the user to save their work, check out/update the PR branch, and rerun. Do not switch, reset, or stash for them. Preserve BASE_SHA, the PR's commit list and all scope flags before merging; cleanup may change HEAD afterward. Unknown scope is not docs-only. DOCS_ONLY=true requires SCOPE_DOCS and no other scope.
Raw lines 213 to 261
Step 1.5: First-run dry-run validation
Check for prior setup confirmation and changed configuration (not proof of a successful deploy):
GSTACK_STATE_ROOT=$(~/.claude/skills/gstack/bin/gstack-paths --get GSTACK_STATE_ROOT); : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}"
SLUG=$(~/.claude/skills/gstack/bin/gstack-slug --get SLUG 2>/dev/null)
if [ ! -f "$GSTACK_STATE_ROOT"/projects/$SLUG/land-deploy-confirmed ]; then
echo "FIRST_RUN"
else
# Check if deploy config has changed since confirmation
SAVED_HASH=$(cat "$GSTACK_STATE_ROOT"/projects/$SLUG/land-deploy-confirmed 2>/dev/null)
CURRENT_HASH=$(sed -n '/## Deploy Configuration/,/^## /p' CLAUDE.md 2>/dev/null | shasum -a 256 | cut -d' ' -f1)
# Also hash workflow files that affect deploy behavior
WORKFLOW_HASH=$(find .github/workflows -maxdepth 1 \( -name '*deploy*' -o -name '*cd*' \) 2>/dev/null | xargs cat 2>/dev/null | shasum -a 256 | cut -d' ' -f1)
COMBINED_HASH="${CURRENT_HASH}-${WORKFLOW_HASH}"
if [ "$SAVED_HASH" != "$COMBINED_HASH" ] && [ -n "$SAVED_HASH" ]; then
echo "CONFIG_CHANGED"
else
echo "CONFIRMED"
fi
fiIf CONFIRMED: Say "Setup was previously confirmed." Go to Step 2; do NOT read the dry-run section.
If FIRST_RUN or CONFIG_CHANGED: Read and execute the dry-run section:
STOP. Before running the first-run dry-run validation — Step 1.5's check returned FIRST_RUN or CONFIG_CHANGED (skip on CONFIRMED), Read ~/.claude/skills/gstack/land-and-deploy/sections/first-run-validation.md and execute it in full. Do not work from memory — that section is the source of truth for this step.Choice A saves the fingerprint and continues to Step 2; B/C stop.
Raw lines 262 to 296
Step 2: Pre-merge checks
Tell the user: "Checking CI status and merge readiness..."
~/.claude/skills/gstack/bin/gstack-ci-gate --repo "$REPO" --pr "$PR_NUMBER" --expect-head "$PR_HEAD" --registration-wait 60It gates on all checks on this head, required or not. Act on line 1, VERDICT <verdict> <sha> (<sha> must be PR_HEAD), never on the exit code. Auth/network/schema errors are ERROR, never "no required checks".
- ERROR, or FAIL on a
required=y|?check: STOP, show the output. - Only
required=nfailures, or NO_CHECKS ("no CI ran on<sha>" after a 60 s re-poll): Step 3.5 must approve it. - PENDING: Step 3. PASS: skip Step 3's wait; continue to Step 3.4, then Step 3.5 before merging.
Also check for merge conflicts:
gh pr view "$PR_NUMBER" --repo "$REPO" --json mergeable -q .mergeableIf CONFLICTING: STOP, resolve conflicts first. Failed/UNKNOWN readback: STOP, readiness is not established.
Raw lines 297 to 322
Step 3: Wait for CI (if pending)
One watcher call, never your own poll loop; a line per real event, else silence:
~/.claude/skills/gstack/bin/gstack-pr-wait "$PR_NUMBER" --repo "$REPO" --until greenExit 0: green; rerun Step 2's gate (a moved head is a new push: restart at Step 1), then Step 3.4. Exit 1 (PR_WAIT_BLOCKED): STOP, show its lines; only a red required=n check can pass Step 3.5. Exit 2 (PR_WAIT_REFUSED): show it.
Raw lines 323 to 337
Step 3.4: VERSION drift detection (workspace-aware ship)
BRANCH_VERSION=$(git show "$PR_HEAD:VERSION" 2>/dev/null | tr -d '\r\n[:space:]')
BASE_VERSION=$(git show "$BASE_SHA:VERSION" 2>/dev/null | tr -d '\r\n[:space:]')
git fetch -q origin "$BASE_BRANCH"
read -r MODE CL < <(~/.claude/skills/gstack/bin/gstack-ship-policy show-effective --base "$BASE_BRANCH" --json |
jq -r 'select(.valid).policy | "\(.queue_mode) \(.changelog)"')
Q=$(bun --no-env-file --config=/dev/null run ~/.claude/skills/gstack/bin/gstack-next-version --base "$BASE_BRANCH" \
--exclude-pr "$PR_NUMBER" --bump patch --current-version "$BASE_VERSION" 2>/dev/null || echo '{"offline":true}')
Q=$(echo "$Q" | jq -r --arg v "$BRANCH_VERSION" '[.claimed[]? | select(.version == $v).pr] as $c | if .no_version
then "NO_VERSION" elif $c != [] then "STOP also claimed by #\($c[0])" elif .offline or (.complete | not)
then "unavailable: claims unread" else "ok" end')
cl() { sed -n 's/^## \[\([^]]*\)\].*/\1/p' | head -2 | xargs; }
H=$(git show "$PR_HEAD:$CL" 2>/dev/null | cl); B=$(git show "$BASE_SHA:$CL" 2>/dev/null | cl)
V=$(awk -v a="$BASE_VERSION" -v b="$BRANCH_VERSION" 'BEGIN { r = "^[0-9]+[.][0-9]+[.][0-9]+([.][0-9]+)?$"
if (a !~ r || b !~ r || split(a, x, ".") != (n = split(b, y, "."))) { print "bad"; exit }
for (i = 1; i <= n && x[i] == y[i]; i++); if (i > n || y[i] < x[i]) { print "low"; exit }
s = y[i] == x[i] + 1; for (j = i + 1; j <= n; j++) s = s && !y[j]; print s ? "one" : "up" }')
if [ "$Q" = NO_VERSION ]; then R=$Q
elif [ "$V" = bad ]; then R="unavailable: bad version"
elif [ "$MODE" = stamp-at-merge ]; then
[ "$V" = one ] && { [ -z "$H" ] || [ "$H" = "$(echo $BRANCH_VERSION ${B%% *})" ]; } && R=ok || R="STOP stamp stale"
elif [ "$V" = low ]; then R="STOP base is at or above it"
elif [ -z "$MODE" ]; then R="unavailable: no policy"
else R=$Q; fi
echo "VERSION_CHECK: $R ($MODE: $BRANCH_VERSION, base $BASE_VERSION)"NO_VERSION: printVERSION check: not applicable (<version_source.reason>); never expect a version-prefixed title, CHANGELOG version header or tag.unavailable: report it; continue to Step 3.5 (CI's version gate is the backstop).ok: continue; a higher sibling claim or a MICRO bump is not drift.STOP stamp stale(stamp-at-merge: not base + one bump, or the top CHANGELOG headings are not it then the base's): STOP; on the PR branch rungstack-restamp --next --base <base> --pr <n> --expect-base <BASE_SHA> --allow-repo-commands, push the stamp diff, wait for CI, rerun.- Other
STOP: STOP with "VERSION drift detected", the verdict and: rerun/shipfrom the feature branch (its ALREADY_BUMPED path reconciles VERSION, package.json, CHANGELOG header and PR title). Never auto-bump or merge here: duplicate versions can overwrite another branch's release notes.
STOP. Before the pre-merge readiness gate (Step 3.5) — the last check before the irreversible merge, Read ~/.claude/skills/gstack/land-and-deploy/sections/readiness-gate.md and execute it in full. Do not work from memory — that section is the source of truth for this step.STOP. Before merging the PR and detecting the deploy strategy (Steps 4-5), Read ~/.claude/skills/gstack/land-and-deploy/sections/merge-and-deploy.md and execute it in full. Do not work from memory — that section is the source of truth for this step.Raw lines 338 to 391
Step 6: Wait for deploy (if applicable)
Unless returning for rollback, set TARGET=production and DEPLOY_SHA=MERGE_SHA. Use the deployment facts from Steps 3.5/5; preserve status separately from canary health. A reachable URL alone does not prove this revision deployed. No configured trigger: do not invent one.
Strategy A: GitHub Actions workflow
If a deploy workflow was detected, find the run triggered by the merge commit:
gh run list --repo "$REPO" --branch "$BASE_BRANCH" --limit 10 --json databaseId,headSha,status,conclusion,name,workflowNameMatch DEPLOY_SHA, workflow and target environment. If no run appears yet, repeat the lookup within the same 20-minute deadline. A name match on another SHA is not evidence.
Poll every 30 seconds:
gh run view <run-id> --repo "$REPO" --json status,conclusionRaw lines 398 to 413Strategy B: Platform CLI (Fly.io, Render, Heroku)
If a deploy status command was configured in CLAUDE.md (e.g., fly status --app myapp), use it instead of or in addition to GitHub Actions polling.
Fly.io: Check the configured app (do not issue fly deploy):
fly status --app {app} 2>/dev/nullLook for started Machines and a release tied to DEPLOY_SHA; time alone is not proof.
Render: Check its release record for the connected branch/revision, then reachability:
curl -sf {production-url} -o /dev/null -w "%{http_code}" 2>/dev/nullPoll every 30 seconds. HTTP 200 proves reachability, not which release is live.
Heroku: Check latest release:
heroku releases --app {app} -n 1 2>/dev/nullRaw lines 414 to 434Strategy C: Auto-deploy platforms (Vercel, Netlify)
When configured to auto-deploy on this merge, wait 60 seconds, inspect the deployment record for DEPLOY_SHA, then Step 7. No record means deployment UNVERIFIED, not success.
Strategy D: Custom deploy hooks
Run only the configured read-only status command. Check its exit code and revision output; a generic health check cannot certify a new deployment.
A recorded command trigger follows Step 5 route 2: it runs from a checkout of the default branch, by the user or by you only with their explicit approval. A zero exit or a reachable URL is not revision proof on its own.
Raw lines 440 to 448Common: Timing and failure handling
Record deploy start time. Show progress every 2 minutes: "Deploy is still running... ({X}m so far). This is normal for most platforms."
Matching revision successfully deployed: record DEPLOY_STATUS=PASSED, duration, and evidence. Continue to Step 7, or Step 5's URL question if none is available.
If deploy fails/cancels: record DEPLOY_STATUS=FAILED, then use AskUserQuestion:
- Re-ground: "The deploy workflow failed after the merge. The code is merged but may not be live yet. Here's what I can do:"
- RECOMMENDATION: Choose A to investigate before reverting.
- A) Let me look at the deploy logs to figure out what went wrong
- B) Revert the merge immediately — roll back to the previous version
- C) Continue to health checks anyway — the deploy failure might be a flaky step, and the site might actually be fine
A: Read gh run view <run-id> --repo "$REPO" --log-failed (or configured platform logs), summarize the cause and evidence limits, then ask: revert (Step 8), inspect health (Step 7), or finish unverified (Step 9). No automatic code edits or redeploy. B: Step 8. C: Step 7 if a URL exists, otherwise Step 5's URL question. A passing canary never erases FAILED deployment evidence.
At 20 minutes (including waiting for a run to appear), ask: A) wait another bounded 20 minutes, B) finish without verification. A resets only the wait deadline and resumes the same lookup/poll; B records pending/unknown deployment and goes to Step 9. Status-query failure is unknown: show the error and offer the same bounded wait or finish choices, not a fabricated success. During rollback monitoring, failure offers logs or a pending report, never a second automatic revert.
Raw lines 449 to 477
Step 7: Canary verification (conditional depth)
Tell the user which target/revision is confirmed or unverified, then check its URL. If browser access is unavailable, record SKIPPED with the reason for this target. Staging choice A returns to its production route; C goes to Step 9 without claiming STAGING VERIFIED. Production goes to Step 9 with incomplete health evidence.
STOP. Before Step 7's URL health check, or any browser step or third-party site action (vendor dashboard, API key, webhook), Read ~/.claude/skills/gstack/land-and-deploy/sections/canary.md and execute it in full. Do not work from memory — that section is the source of truth for this step.Raw lines 478 to 489
Step 8: Revert (if needed)
Enter only after the user's explicit rollback choice. Explain that this adds inverse commits; production is not restored until rollback deploys and health is checked. Require a clean worktree, fetch BASE_BRANCH from REPO, switch to the local base and fast-forward only to that fetched tip. Dirty, diverged, or occupied base: STOP with ROLLBACK PENDING, never reset/force or discard work.
Inspect the actual landed commit, not just the requested merge method:
git show --no-patch --format='%H %P' "$MERGE_SHA"- Two parents: verify parent 1 is the base-side history, then
git revert -m 1 "$MERGE_SHA" --no-edit. - One-parent confirmed squash:
git revert "$MERGE_SHA" --no-edit. - Rebase merge: establish the exact landed commit range for this PR and revert it newest-first.
mergeCommit.oidalone is only the last commit, not the range. Unknown range/method (including an external merge) or other parent shapes: STOP with ROLLBACK PENDING and request manual rollback; do not guess.
Conflicts: stop, show git status and the attempted command, leave resolution to the user. After a clean revert, record REVERT_SHA and push to the selected base: git push "https://github.com/$REPO.git" "HEAD:refs/heads/$BASE_BRANCH". If branch protection rejects it, keep the commit, create revert/pr-<number>-<timestamp> there, push that branch and open a revert PR against BASE_BRANCH. Report its URL and ROLLBACK PENDING; never merge it without separate approval. Other push errors stop with the error and pending status, not a protection bypass.
After a successful base push, set ROLLBACK=true, TARGET=production, DEPLOY_SHA=REVERT_SHA, and reset production deployment/health to UNKNOWN/SKIPPED for that revision. Keep original/staging evidence separately. Monitor via Steps 6-7 without resetting those values. Only a confirmed rollback deployment and healthy production canary yields REVERTED (or a confirmed base revert where no deploy is required). All incomplete, failed, skipped or PR-based rollback paths go to Step 9 as ROLLBACK PENDING. Preserve the original merge SHA in the report.
Raw lines 490 to 527
Step 9: Deploy report
Choose the first matching verdict; never infer deployment success from merge or HTTP 200:
| Evidence | Verdict |
|---|---|
| Rollback requested, not yet confirmed on base and live/healthy (when deploy applies) | ROLLBACK PENDING |
| Rollback confirmed as described in Step 8 | REVERTED |
| Any accepted target-health failure | DEGRADED |
| User chose staging-only and staging passed | STAGING VERIFIED — PRODUCTION UNVERIFIED |
| Explicit no-deploy confirmation or Step 5's docs-only skip | MERGED — NO DEPLOY NEEDED |
| Matching production deployment PASSED and production HEALTHY | DEPLOYED AND VERIFIED |
| Matching production deployment PASSED but canary skipped/unavailable | DEPLOYED (UNVERIFIED) |
| Everything else, including failed/pending/unknown deploy even with a healthy old site | MERGED (UNVERIFIED) |
Display LAND & DEPLOY REPORT and save .gstack/deploy-reports/{date}-pr{number}-deploy.md (date = UTC YYYY-MM-DD). Include PR/title/repository, head → base, approved head, merge timestamp/SHA/method/path, first-run status, CI/review status and warnings, scope, separate deploy/staging/canary outcomes with evidence links/errors, console count, load time, screenshot paths (N/A when not checked), verdict and next action. Record dry-run, CI wait, queue, deploy, staging, canary and total durations in seconds; skipped stages have duration 0 with a reason, never a fabricated pass. Inline review is passed/skipped/not-needed; inline fixes stopped before merge and cannot appear here. For rollback include revert SHA or PR URL and unresolved work.
GSTACK_STATE_ROOT=$(~/.claude/skills/gstack/bin/gstack-paths --get GSTACK_STATE_ROOT); : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}"
mkdir -p .gstack/deploy-reports
SLUG=$(~/.claude/skills/gstack/bin/gstack-slug --get SLUG 2>/dev/null)
mkdir -p "$GSTACK_STATE_ROOT"/projects/$SLUGPass one JSON entry to ~/.claude/skills/gstack/bin/gstack-review-log '<JSON>' for the dashboard's branch-scoped JSONL log. status is SUCCESS only for DEPLOYED AND VERIFIED or MERGED — NO DEPLOY NEEDED, REVERTED for confirmed rollback, otherwise INCOMPLETE. Keep the full verdict and independent evidence states:
{"skill":"land-and-deploy","timestamp":"<ISO>","status":"<SUCCESS/REVERTED/INCOMPLETE>","verdict":"<verdict>","pr":<number>,"merge_sha":"<sha>","merge_path":"<auto/direct/queue/external>","first_run":<true/false>,"deploy_status":"<PASSED/FAILED/PENDING/UNKNOWN/NOT_NEEDED>","verification":"<HEALTHY/DEGRADED/SKIPPED>","staging_status":"<VERIFIED/DEGRADED/SKIPPED/N/A>","review_status":"<observed status>","dry_run_s":<N>,"ci_wait_s":<N>,"queue_s":<N>,"deploy_s":<N>,"staging_s":<N>,"canary_s":<N>,"total_s":<N>}Raw lines 528 to 569
Step 10: Suggest follow-ups
State the verdict in plain English. Verified: changes are live. Unverified/degraded: name the missing evidence/issues and the exact workflow/status command or /canary <url> to check next. No deploy needed: merged, verification skipped for the stated reason. Staging-only: production remains unverified, not necessarily undeployed. Rollback pending: identify who must resolve conflicts, merge the revert PR, or verify its deploy. REVERTED: cite rollback evidence; do not claim the original branch survived cleanup. Offer /canary <url> for extended monitoring, /benchmark <url> when performance matters, and /document-release when docs need updating.
Raw lines 570 to 582
Section self-check (before you finish)
You ran a carved skill. For your situation, list every section the Section index named as applying, and confirm you issued a Read for each one (a CONFIRMED Step 1.5 correctly skips the dry-run section). Missing Read: STOP and read the source now. Recheck read-only evidence; never redo a merge/deploy because a section was missed.
Raw lines 583 to 591
Important Rules
- Never force-push, bypass CI, replay a confirmed merge, or hide missing evidence.
- Auto-detect facts; ask when unknown or when an explicit approval gate applies.
- Step 3 is one
gstack-pr-waitcall; elsewhere poll at the stated interval (30 s for merge readback and deploy) with progress lines. - After merge failures, offer approved rollback when appropriate; never revert a rollback automatically.
- Verify once;
/canaryprovides extended monitoring. Rechecks require the user's choice. - Use
--delete-branch; reconcile failed cleanup non-destructively with confirmation.
From garrytan/gstack at 3f79d81, 2026-11-01. Skills read by DeepSeek V4.1 Flash on 2026-11-04. Summary and techniques by Claude Opus 5.5 on 2026-11-06.