.agents/skills/harness-cleanup/SKILL.md
Phase skill: post-merge cleanup — merge the approved PR, verify Railway deploy, finalize Linear status, remove worktree
npx skillsauth add cowcow02/agentfleet harness-cleanupInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
After the human approves the PR, finalize the work: merge the PR, verify the Railway deployment is healthy, move the Linear ticket to Done, record the outcome, and remove the worktree.
This phase only runs after the review phase has flipped from waiting to done (i.e. the human gave approval). The agent performs the actual merge — the human's role ends at "approved, go ahead."
Read state outputs — pick up pr_number, pr_url, branch, worktree, ticket id, and any RAILWAY_* config from earlier phases.
Confirm PR is ready to merge:
gh pr view <pr-number> --json state,mergeable,mergeStateStatus
state == "MERGED" already (rare — manual merge by human): skip to step 4mergeable != "MERGEABLE": surface to human with the reason, set phase to blockedMerge the PR:
gh pr merge <pr-number> --squash --delete-branch
--squash keeps master history linear--delete-branch removes the remote branch (the worktree's local branch is removed in step 8)Sync the main repo to merged master — subsequent commits (e.g. cleanup section) land on up-to-date master, not on the now-stale feature branch.
The main repo is the common dir's parent of the worktree — git rev-parse --git-common-dir gives <repo>/.git, so its parent is the main repo root:
REPO_ROOT=$(cd "$WORKTREE_PATH" && dirname "$(git rev-parse --git-common-dir)")
git -C "$REPO_ROOT" fetch origin master
git -C "$REPO_ROOT" merge --ff-only origin/master
This is more robust than parsing git worktree list --porcelain (which assumed the first entry was the main repo — true today but not guaranteed if the worktree ordering ever changes).
Verify Railway deployment — poll API + Web healthchecks until 200 or 5-minute timeout:
API_HEALTH_URL="${RAILWAY_API_HEALTH_URL:-https://api.agentfleet.app/health}"
WEB_HEALTH_URL="${RAILWAY_WEB_HEALTH_URL:-https://app.agentfleet.app/}"
API_STATUS=000
for i in $(seq 1 30); do
API_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$API_HEALTH_URL")
[ "$API_STATUS" = "200" ] && break
sleep 10
done
WEB_STATUS=000
for i in $(seq 1 30); do
WEB_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$WEB_HEALTH_URL")
[ "$WEB_STATUS" = "200" ] && break
sleep 10
done
deploy_verified: true in state outputs with both URLs and statusesblockedRAILWAY_API_HEALTH_URL / RAILWAY_WEB_HEALTH_URL are not configured for this repo, skip with a note in the conversation fileUpdate Linear ticket to "Done" — only on Railway success (or on skipped Railway with explicit note). Use mcp__plugin_linear_linear__save_issue with state: "Done". Skip entirely for plain-text tasks (no Linear ticket).
Record to conversation file — the conversation file is now on master (it was committed by harness-ship and then merged). Update the master copy in the main repo, NOT the worktree copy:
cd "$REPO_ROOT"
Insert before the ## Harness Issues marker in .harness/conversations/<task-id>.md (use Edit tool with ## Harness Issues as the anchor — do NOT literally append, that would land below the issues section):
## Cleanup
**Merged at:** <timestamp>
**Railway deploy:** verified (api: <api_status>, web: <web_status>) / skipped (no URLs configured) / failed
**Linear final status:** Done
## Harness Issues section since that section is last.Commit the cleanup section to master:
git add .harness/conversations/<task-id>.md
git commit -m "chore: record cleanup phase to <task-id> conversation log"
git push
If there are no changes, skip silently.
Remove worktree — only after every step above succeeded. Hard safety check first:
cd "$WORKTREE_PATH"
DIRTY=$(git status --porcelain)
if [ -n "$DIRTY" ]; then
echo "ERROR: worktree has uncommitted changes — refusing to remove."
echo "$DIRTY"
# Surface to human, do NOT use --force
exit 1
fi
cd "$REPO_ROOT"
git worktree remove "$WORKTREE_PATH"
Never use --force. A dirty worktree at this point means something was missed in harness-ship step 1 (staging the conversation file) or in step 7 above (committing the cleanup section). Surface and investigate.
## Cleanup sectiongh pr merge fails (branch protection, conflicts, failing checks), surface to human with the error — do not bypass branch protectionblocked with that reason and stop--force removetesting
Launcher — pick up a Linear ticket or task description and drive it through the full phased workflow (pickup → understand → plan → implement → quality → verify → ship).
development
Phase skill: start the app on an isolated per-task environment and verify the deliverable works — browser checks via Claude in Chrome for UI, HTTP calls for API
development
Phase skill: explore the codebase to understand what needs to change for the ticket
testing
Phase skill: commit changes, push branch, create a GitHub pull request, and watch CI to green