| name | land |
| description | Session completion protocol - the opposite of "takeoff". Use this skill whenever the user says "land", "/land", "land the plane", "land it", "let's land", "land this", "bring it in", "wrap it up", "land the plan", "land plane", "time to land", "ok land", "go ahead and land", or any variation that signals they want to finish, close out, ship, or wrap up the current session's work. Executes the full commit → push → PR → handoff checklist without asking. If the user's message contains "land" in the context of finishing work, invoke this skill — it is a keyword trigger, not an exact match. |
| argument-hint | [optional: extra context, e.g. 'skip PR' or 'no handoff notes'] |
Land the Plane Protocol
The session completion counterpart to /takeoff. Where takeoff starts work by surfacing the backlog, /land finishes work by running the full commit → push → PR → handoff checklist.
Trigger
Any variation of: land, /land, land the plane, land it, let's land, land this, bring it in, wrap it up, land the plan, land plane, time to land, ok land, go ahead and land.
This is a keyword trigger, not an exact match. If the user's message contains "land" in the context of finishing/wrapping up work, invoke this protocol. When in doubt, invoke it.
Core principle
"Landing" means commit, push, and create a PR — it does not mean merge. A PR is how humans review agent work; no PR means no review means no trust. Never merge unless the user explicitly says "merge this PR".
Work is not complete until git push succeeds. If push fails, resolve and retry until it works. Do not stop at "ready to push when you are" — you must push.
Execution
Run the checklist in order, completely, without asking. Each step is non-negotiable.
Step 1: File remaining work
Review what was worked on this session. Capture anything that's unfinished, deferred, or follow-up so it doesn't vanish when the session closes.
- If the project has Backlog.md (a
backlog/ directory at repo root), create tasks for unfinished/follow-up work via the backlog CLI or mcp__backlog__task_create.
- Otherwise, gather remaining work into a short handoff list and surface it to the user at Step 10.
Skip silently if nothing remains.
Step 2: Run quality gates (only if code changed this session)
Run the project's build and test commands. Detect the stack first — only run gates for toolchains the repo actually uses. A non-zero exit must halt the routine; never suffix gates with || true.
if [ -f pnpm-lock.yaml ]; then
pnpm build && pnpm lint
elif [ -f package-lock.json ] || ([ -f package.json ] && [ ! -f pnpm-lock.yaml ] && [ ! -f yarn.lock ]); then
npm run build && npm run lint
fi
if [ -f pyproject.toml ] || [ -f setup.py ] || [ -f requirements.txt ]; then
pytest && ruff check .
fi
if [ -f go.mod ]; then
go build ./... && go vet ./...
fi
if [ -f Cargo.toml ]; then
cargo build && cargo test
fi
If build or tests fail, fix them before proceeding. Do not skip this step. A broken build does not ship. Because the gates are no longer suffixed with || true, a failure here will halt the routine — which is the point.
If no code changed (docs-only, config-only, planning-only sessions), skip quality gates and note that in the handoff.
Step 3: Update task status (if project has task tracking)
Mirror Step 1's conditional + literal-command pattern so a fresh agent — one cold-loading the skill on a session where the user said "land it" — can mechanically follow the CLI shape rather than guessing it from prose:
if command -v backlog >/dev/null 2>&1 && [ -d backlog ]; then
backlog task edit TASK-XYZ --status Done
backlog task edit TASK-XYZ \
--status "In Progress" \
--notes "<one-line implementation context, commit refs, what's blocking>"
fi
Substitute the actual task IDs from this session. Skip silently when the backlog CLI is absent — the conditional guard covers projects without backlog tooling.
If the project uses backlog_task_id in plan frontmatter, ensure status reflects reality.
Step 4: Commit all changes
Stage specific files — never git add -A or git add .. That risks pulling in .env, credentials, or large binaries.
git status
git add <specific-files>
git commit -m "<type>: <summary>"
If there are no changes, skip. Do not create empty commits.
Step 5: PUSH TO REMOTE (MANDATORY)
Work is not complete until this step succeeds.
branch=$(git branch --show-current)
if git rev-parse --verify "origin/$branch" >/dev/null 2>&1; then
git pull --rebase origin "$branch"
fi
git push -u origin "$branch"
git status
If push fails (conflicts, hook rejection, branch protection), resolve and retry until it works. Do not hand off with unpushed commits.
Step 6: Create or update the PR
A PR is the review artifact. Agent work without a PR has no trust surface.
gh pr view exits 0 for CLOSED and MERGED PRs as well as OPEN ones — so a bare gh pr view is unsafe as an "is there a PR?" check. Capture state explicitly and only treat OPEN as a usable existing PR; otherwise create a fresh one.
pr_state=$(gh pr view --json state -q .state 2>/dev/null || echo "NONE")
if [ "$pr_state" = "OPEN" ]; then
:
else
gh pr create --fill --web=false
fi
When creating the PR body, summarize the full branch diff (not just the latest commit). Resolve the default branch dynamically — it's not always main:
default_branch=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@')
if [ -z "$default_branch" ]; then
default_branch=$(git rev-parse --verify origin/main >/dev/null 2>&1 && echo "main" || echo "master")
fi
git log "origin/$default_branch..HEAD" --oneline
git diff "origin/$default_branch...HEAD" --stat
Include a test plan checklist in the body. Share the PR URL at handoff.
Never merge the PR unless the user explicitly says "merge this PR". Landing ≠ merging.
Step 7: Clean up
git stash list
If working in a worktree:
- PR open/pending review: leave the worktree in place so review feedback can be addressed without re-cloning.
- Work merged or abandoned: remove the worktree (
git worktree remove <path>) and delete its branch (git branch -d <name>).
Step 8: Verify
Confirm a clean state:
git status
if branch="$(git branch --show-current)" && [ -n "$branch" ]; then
if git rev-parse --verify --quiet "refs/remotes/origin/$branch" >/dev/null; then
if [ -n "$(git log "origin/$branch..HEAD" --oneline)" ]; then
echo "BLOCKED: unpushed commits on $branch — push before landing." >&2
git log "origin/$branch..HEAD" --oneline
exit 1
fi
echo "OK: all commits pushed to origin/$branch."
else
echo "BLOCKED: $branch has no origin/$branch upstream — push the branch before landing." >&2
exit 1
fi
else
echo "(detached HEAD — not on a branch; unpushed-commits check skipped)"
fi
If the check reports BLOCKED (non-zero exit), loop back and push. Do not hand off
a dirty or unpushed tree. Detached HEAD is the one state that legitimately skips
the check — every branch state must be fully pushed before landing.
Step 9: Capture session state
Persist a written record of the session so the next agent (or human) can resume with full context, not just the verbal handoff in Step 10.
If the project tracks sessions in docs/sessions/, .sessions/, or an equivalent directory, append a short note there. Otherwise drop a brief handoff into the repo's working notes (e.g., docs/handoffs/<date>.md) capturing: branch, PR URL, accomplished, next up, blockers.
Run unconditionally — even on docs-only or planning-only sessions. The note is cheap and the recovery value is high.
Step 10: Hand off
Provide a concise summary for the next session:
- Accomplished — what shipped (with task IDs if applicable)
- Next up — what's queued (with task IDs if applicable)
- Blockers / gotchas — anything that tripped you up or is waiting on a decision
- Branch — current branch name
- PR — PR URL from Step 6
Keep it scannable. The next session (human or agent) should be able to take off from this handoff without re-reading the whole transcript.
Step 11: Final banner
After the handoff summary, emit a single final line:
🛬 PLANE LANDED — NICE WORK
This must be the last line of output — no content after it, no code fence, no trailing heading. The banner is a completion marker, not a "we tried" marker: emit it only when the routine completes successfully (including the clean-tree / nothing-to-commit path where Step 5 is skipped because there's nothing to push). If git push never succeeds, a quality gate fails and halts the routine, or the PR step errors out and cannot be resolved, do not emit the banner.
Critical rules
These are non-negotiable when /land is invoked:
- NEVER stop before pushing. Unpushed work is stranded work.
- NEVER say "ready to push when you are." You push. That is the job.
- NEVER skip quality gates. Broken code does not ship.
- NEVER merge the PR unless the user explicitly says "merge this PR".
- NEVER use
git add -A or git add .. Stage specific files.
- NEVER bypass hooks (
--no-verify, --no-gpg-sign) unless the user explicitly asks. If a hook fails, investigate and fix the root cause.
- If push fails, resolve and retry until it succeeds.
- Always end successful landing output with the
🛬 PLANE LANDED — NICE WORK banner line. Do not emit the banner on failure paths (push failed, quality gate halted the routine, PR step errored out with no resolution).
Project-specific considerations
Some repos have local conventions layered on top of this protocol — read AGENTS.md at the repo root for project-specific rules (e.g., branch protection, PR comment workflows, backlog linkage requirements). Project rules override these defaults where they conflict.