Create a fresh git branch. Use for an explicit /new-branch request or when a task-owned worktree needs a branch to ship detached work. Keep platform-assigned Builder.io and Fusion branches in place.
52
65%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Fix and improve this skill with Tessl
tessl review fix ./.agents/skills/new-branch/SKILL.mdUse this skill when the user invokes /new-branch, asks for a fresh branch, or
/ship needs a branch in a dedicated task-owned worktree. Safe branch
operations in that worktree need no extra permission. Keep a shared checkout
on its current branch. When an explicit /ship or PR-publishing request cannot
safely use that checkout, create a managed task-owned worktree and branch
without asking. Base new PRs on fresh origin/main. For an existing PR update,
base the task worktree on the fetched live PR head so its ancestry remains
publishable; carry only this task's changes. Follow babysit-pr to resolve the
PR head repository and ref, update it with a normal fast-forward, and recover
safely if its OID moves. If peer or unpublished PR work blocks recovery,
preserve it and report exact blockers without asking.
Platform-assigned Builder.io and Fusion branches stay in place; never touch
another checkout or move a branch used by another worktree.
Steve's standing instruction applies across tasks and sessions: needed, safe branch creation or switching inside a task-owned worktree needs no repeated permission. This does not authorize changing the shared checkout's branch, moving a branch used by another worktree or platform, or destructive branch operations.
If the current branch is already suitable, keep using it. When a detached task-owned worktree needs a branch to ship, create one without pausing for permission.
These are mistakes other agents have made that stranded concurrent work:
In a task-owned worktree, choose a safe branch and proceed without asking. In a shared checkout, keep the current branch. For an explicit ship or PR request, automatically isolate the work in a managed task-owned worktree if needed; for other tasks, use the current branch unless the user gave an exact branch operation.
For an existing PR update from an unsafe shared checkout, follow the live-head
and fast-forward rule above. For a new PR, fetch origin/main, inspect the
current branch, dirty paths, and worktree ownership, then create the new branch
from the freshest base that preserves all current work. Never stash changes as
a shortcut.
Before creating the branch, always verify that origin/main contains the most recently merged PR. If you just merged a PR (or know one was recently merged), run:
git fetch origin main
gh pr list --state merged --base main --limit 1 --json number,mergedAt,mergeCommit --jq '.[0]'
git log origin/main --oneline -1Compare the merge commit SHA. If origin/main doesn't include it yet, wait and re-fetch — GitHub can take a few seconds to update after a squash merge. Never create a branch off stale main. Creating a branch that's missing a just-merged PR causes chaos: subsequent work assumes the merged code is there, leading to conflicts, regressions, and duplicated changes.
/ship rotationDuring /ship, use this path after verifying the merge commit on origin/main.
In a task-owned worktree, this safe rotation needs no extra permission. Confirm
there are no unpushed commits on any path and no dirty publishable paths; only
learnings.md, bridge/**, and data/** may remain dirty. If any unpushed
commit remains, keep the source branch checked out and report the commit hashes
instead of rotating. This preserves commits excluded from /ship:push. Use the
preserved-path exception only for this post-merge rotation; setup-time branch
creation or switching still requires every dirty path to belong to this task.
The excluded paths stay unchanged across rotation.
immutable ship_merge_head_oid captured
before the guarded merge (from the Codex watcher prompt or foreground task
transcript, or the Claude /goal or foreground task transcript); never
substitute the live headRefOid after merge. This remains verifiable if GitHub
deletes the source branch after squash merge. Fetch origin
and inspect both local and remote source-branch tips before choosing a name and
creating directly from origin/main:
if ! git fetch --no-prune origin; then
echo "Cannot refresh origin; keep the source branch." >&2
exit 1
fi
branch=$(git branch --show-current)
if [ -z "$branch" ]; then
echo "Detached checkout; keep the current worktree unchanged." >&2
exit 1
fi
ship_head="<persisted-ship_merge_head_oid>"
if ! git cat-file -e "$ship_head^{commit}"; then
echo "Cannot verify the immutable merged PR head; keep the source branch." >&2
exit 1
fi
if ! git merge-base --is-ancestor "$ship_head" HEAD; then
echo "Local HEAD does not contain the merged PR head; keep the source branch." >&2
git log --oneline HEAD --not "$ship_head"
exit 1
fi
remote_line=$(git ls-remote --heads origin "refs/heads/$branch") || {
echo "Cannot inspect the remote source branch; keep the source branch." >&2
exit 1
}
remote_ref="refs/remotes/origin/$branch"
local_unpublished=$(git log --oneline "$ship_head"..HEAD) || {
echo "Cannot inspect local commits; keep the source branch." >&2
exit 1
}
remote_unpublished=
if [ -n "$remote_line" ]; then
if ! git fetch --no-prune origin "refs/heads/$branch:$remote_ref"; then
echo "Cannot refresh the remote source branch; keep the source branch." >&2
exit 1
fi
if ! git merge-base --is-ancestor "$ship_head" "$remote_ref"; then
echo "Remote source branch diverged from the merged PR head; keep the source branch." >&2
git log --oneline "$remote_ref" --not "$ship_head"
exit 1
fi
remote_unpublished=$(git log --oneline "$ship_head".."$remote_ref") || {
echo "Cannot inspect remote commits; keep the source branch." >&2
exit 1
}
fi
if [ -n "$local_unpublished" ] || [ -n "$remote_unpublished" ]; then
if [ -n "$local_unpublished" ]; then
printf 'Local commits after the merged PR head:\n%s\n' "$local_unpublished"
fi
if [ -n "$remote_unpublished" ]; then
printf 'Remote commits after the merged PR head:\n%s\n' "$remote_unpublished"
fi
echo "Keeping the source branch; report these commits instead of rotating."
else
dirty_publishable=$(git status --porcelain --untracked-files=all -- . \
':(exclude)learnings.md' ':(exclude)bridge/**' ':(exclude)data/**') || {
echo "Cannot verify the working tree; keep the source branch." >&2
exit 1
}
if [ -n "$dirty_publishable" ]; then
printf 'Dirty publishable paths:\n%s\n' "$dirty_publishable" >&2
echo "Keep the source branch until publishable paths are clean." >&2
exit 1
fi
# Replace with a unique name following the Branch naming rules above.
new_branch="<github-username>/changes-N"
git switch -c "$new_branch" origin/main || {
echo "Could not create the next branch; keep the source branch." >&2
exit 1
}
fiThese unfiltered checks cover local and remote commits on every path; do not
use /ship's excluded-path filter for rotation.
After post-merge rotation, verify the new branch points at current origin/main
and excluded local changes are still present. For other branch creation, verify
the branch includes the task commits and dirty work it was meant to carry. Do
not check out or pull a local main, stash, force, reset, or touch another
worktree. If Git refuses to carry a path, leave the current checkout intact.
Retaining the source branch because it has unpublished commits is a safe
disposition; platform-assigned Builder.io and Fusion checkouts stay on their
assigned branches and do not use the rotation path.
In a task-owned worktree, branch creation or switching needed for the task is
already authorized; do not pause to ask. Before moving, record
git status --short --untracked-files=all and classify every staged, unstaged,
and untracked path. A switch carries the whole index and worktree, so proceed
only when every dirty path belongs to this task. If any path is unrelated or
incomplete, keep the checkout in place and report the exact paths without
asking again. Fetch origin/main, inspect commits and
git worktree list --porcelain, then create an unused branch without stashing
or changing another worktree. Carry current commits and local changes. Use fresh
origin/main as the base when that preserves the task's work; otherwise create
from the current task head and reconcile only when the ship workflow requires
it. In a shared checkout, keep its branch unchanged. An explicit ship or
PR-publishing request authorizes a managed task-owned worktree when needed;
follow the new-PR or existing-PR base rule above, classify the full path set,
and carry only this task's changes. If the task's changes cannot be isolated
safely, preserve all state and report the exact paths or commits without
asking for branch or worktree permission.
<github-username>/changes-N, for example steve8708/changes-545, where N is at least 50<github-username> with gh api user --jq .login; do not substitute a display name or local git author nameorigin refs matching changes-N, whether legacy unprefixed or already username-prefixed, so the sequence does not reset<github-username>/changes-50a941a2e
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.