Create Branch
Create a git branch following the repository's naming conventions with GitHub or Linear issue integration. Supports GitHub issue branches (issue-<number>-<slug>), Linear ticket branches (<team>-<number>-<slug>), and special prefix branches (hotfix, trivial, maintenance, proposal, security).
When to Use
- When creating a new branch from a GitHub issue
- When creating hotfix, trivial, maintenance, proposal, or security branches
- When invoked from
/autopilot:planfor automatic branch creation - When invoked from other skills
Input
Arguments: $ARGUMENTS
Expected forms:
<ISSUE-NUMBER>— GitHub issue number (e.g.,123or#123). Used to fetch the issue and to build the branch nameissue-<number>-<slug>.<LINEAR-ID>— Linear identifier (e.g.,ENG-123, matching^[A-Z]+-[0-9]+$) when the project lists alineartracker inpackage.jsonagents.trackers. Builds<team>-<number>-<slug>(the id lowercased).<ISSUE-NUMBER|LINEAR-ID> "<description>"— issue identifier plus custom branch slug description--start— Linear only: also move the Linear ticket to "In Progress" after the branch is created (best-effort). Ignored for GitHub and special-prefix branches.--hotfix "<description>"/--trivial "<description>"/--maintenance "<description>"/--proposal "<description>"/--security "<description>"— special prefix branches without a GitHub issue (use--securityfor code-scanning alert fixes →security-<slug>)--autopilot— non-interactive mode used by/autopilot:run. Skips the Phase 0 preflight, which the calling chain already ran, and the Phase 5 confirmation prompt, which only special-prefix branches still reach. Issue and Linear branches are created directly for every caller, so the flag has no effect on their naming. Conflict resolution (Phase 4) and validation errors still surface.
Input resolution
Arguments are optional. When $ARGUMENTS is empty OR a field is missing, resolve from context in this order:
- Issue number —
$ARGUMENTS→ parse current branch name for^issue-([0-9]+)→ prompt user only if none found and no special prefix flag is present. - Description —
$ARGUMENTS→ generate from GitHub issue title via Phase 3 rules → no user prompt (auto-generate always succeeds). - Special prefix flags (
--hotfix/--trivial/--maintenance/--proposal/--security) —$ARGUMENTSonly. Never inferred. Default: none. --autopilot—$ARGUMENTSonly. Never inferred. Default:false(interactive mode).- Repository conventions — read
CONTRIBUTING.mddirectly from the repository root.
Phase 0: Preflight Check
Autopilot bypass: parse $ARGUMENTS for --autopilot before anything else — the same parse Phase 1 step 1 performs, moved here so this phase can read it. When the flag is present, skip this phase entirely. The calling chain ran its own preflight before any git mutation, so the history-policy gate is already installed, and the remaining branch-mode checks cannot change the outcome: Phase 6 fetches origin and branches from origin/main itself, so a stale local main never reaches the new branch.
Otherwise invoke Skill(autopilot:preflight-check) with mode: branch from this conversation context. The skill validates current branch state, detects stale merged branches, and ensures main is up to date before a new branch is created. If it outputs a "cancelled" message, stop immediately — do not proceed to Phase 1.
Phase 1: Input Validation
Parse
$ARGUMENTS(shell-quoted positional tokens):- Check for
--autopilot: if present, strip it from the arguments and setautopilotMode = true. OtherwiseautopilotMode = false. - Check for
--start: if present, strip it and setstartIssue = true(Linear only; see Phase 6). OtherwisestartIssue = false. - Check for special prefix flags:
--trivial,--hotfix,--maintenance,--proposal,--security - If flag found: extract description from remaining arguments
- If no flag: extract the first argument as the issue identifier (GitHub number or Linear id), optional description
- If
$ARGUMENTSis empty, fall back to Input resolution (see above).
- Check for
If special prefix flag detected:
- Try to extract description from the conversation history
- Description is REQUIRED — error if missing:
Description is required for special prefix branches (e.g., /autopilot:branch-create --trivial "fix typo") - Multiple prefix flags not allowed — error:
Only one special prefix flag allowed - Skip Phase 2 (no GitHub issue to fetch)
If no flag, validate the issue identifier and resolve the provider (read
package.jsonagents.trackerswith the Read tool):- Linear — the identifier matches
^[A-Z]+-[0-9]+$(e.g.,ENG-123) AND alineartracker is configured: setprovider = linear. - GitHub — the identifier matches
^#?[0-9]+$(strip a leading#): setprovider = github. - If invalid:
Invalid issue identifier. Expected a GitHub number (e.g., 123 or #123), a Linear id (e.g., ENG-123) for a linear-tracked project, or a --trivial/--hotfix/--maintenance/--proposal/--security flag
- Linear — the identifier matches
Phase 2: Fetch GitHub Issue
Skip this phase entirely for special prefix flag branches (--hotfix, --trivial, --maintenance, --proposal, --security).
If provider is linear: read linear-branch.md and follow its fetch path instead of the GitHub steps below.
Determine the repository and bind it to
REPOso everyghcall in this phase targets the same repo (important in worktrees and multi-remote checkouts):REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)Fetch the issue (include
assigneesso the self-assign step needs no extra call):gh issue view <ISSUE-NUMBER> -R "$REPO" --json title,body,state,assigneesExtract:
- Issue title (for slug generation)
- Issue body (for context)
- Current state (warn if already closed)
If issue not found:
- Error:
Issue #<ISSUE-NUMBER> not found in <repo>
- Error:
Self-assign the current user — idempotent and best-effort; it must never block branch creation.
Assigning the issue the moment work starts keeps "who is working on what" accurate. This runs on every issue branch (special-prefix branches skip Phase 2, so they never assign). On ANY failure, emit the status line and continue to Phase 3 — the branch is the deliverable; assignment is a side effect.
Emit exactly one status (same vocabulary as the canonical agent):
@<login> (just assigned)@<login> (already assigned)unassigned — gh not authenticatedunassigned — issue closedunassigned — permission denied or assignee limit reachedunassigned — gh edit error: <first line of stderr>
Execution steps: read
references/self-assign.mdat this step.
Phase 3: Generate Branch Slug
If special prefix branch:
- Normalize description to lowercase kebab-case
- Remove special characters (keep only
a-z0-9-) - Construct branch name:
<prefix>-<slug>(prefix lowercased) - Example:
--hotfix+"memory leak in editor"→hotfix-memory-leak-editor;--security+"tainted format string"→security-tainted-format-string - Validate total length ≤ 100 characters — if over 60, suggest shorter description; if over 100, require it
If custom description provided:
- Normalize to lowercase kebab-case
- Remove special characters (keep only
a-z0-9-) - Use as the slug
If no description provided:
- Analyze issue title and body
- Generate a short, meaningful business-focused slug
- Rules:
- Paraphrased/summarized, NOT mechanical title-to-slug conversion
- Lowercase with hyphens only
- 3-5 words maximum
- Capture the essence of what's being done
Construct full branch name:
- GitHub:
issue-<number>-<slug> - Linear:
<team>-<number>-<slug>— the Linear id lowercased, then the slug (e.g.ENG-123→eng-123-<slug>) - Aim for under 60 characters; reject if over 100
- If too long: regenerate shorter slug
Phase 4: Check for Conflicts
Formatting Note: Read askuserquestion-format.md and apply it before composing the question parameter.
Check local branches:
git show-ref --verify --quiet refs/heads/<branch-name>Check remote branches:
git ls-remote --heads origin <branch-name>Handle conflicts using AskUserQuestion tool:
If branch exists locally or remotely, present options:
Tool parameters:
question: "Branch already exists. How would you like to proceed?"header: "Conflict"options: [ { label: "Checkout existing", description: "Switch to the existing branch" }, { label: "Create with suffix", description: "Create -2" }, { label: "Different description", description: "Enter a new description for the slug" } ]multiSelect: false
Phase 5: Confirm Special-Prefix Branch Name
Issue-input bypass: If provider is github or linear, skip this entire phase and proceed directly to Phase 6 with the resolved branch name. Do NOT call AskUserQuestion. The name is derived from an issue the user already chose, so confirming it carries no decision — and a name that turns out wrong costs a rename before any PR exists.
Autopilot bypass: If autopilotMode is true (from Phase 1), skip this entire phase and proceed directly to Phase 6 with the resolved branch name. Do NOT call AskUserQuestion.
For a special-prefix branch without --autopilot, read special-prefix-dialog.md, obtain the branch-name decision, then continue to Phase 6 only after confirmation.
Phase 6: Execute
Validate the branch name (MANDATORY, before any git command): read the canonical branch-name regex from pr-title-grammar.md and match the fully constructed <branch-name> against it, including the 100-character limit. The name must be exactly what the earlier phases constructed — never decorate it with extra path segments or prefixes (feature/issue-123-slug is invalid; the convention contains no /). On mismatch, regenerate the slug once via the Phase 3 rules and re-validate; if the name still fails, stop with an error naming the rejected name and the expected formats — the branch is NOT created. This gate is the last line before git checkout -b: a name that fails here in seconds would otherwise fail the contributing-check CI on an opened PR, where the only fix is a fresh branch and a fresh PR.
Fetch latest remote and create branch from origin/main:
git fetch origin git checkout -b <branch-name> origin/mainPush with tracking:
git push -u origin <branch-name>If
providerislinearAND--startwas passed: follow Start the ticket, then include its outcome in the result below. Skip this reference for every other branch.Output result:
✓ Branch created: <branch-name> ✓ Pushed to origin with tracking Next steps: - Make your changes - Use /autopilot:commits-create to create commits - Use /autopilot:pr-create when readyWhen
--startwas passed for a Linear ticket, add the step 3 outcome line after the push confirmation —✓ Ticket <LINEAR-ID> moved to In Progresson success, or theissue not started — <reason>line on failure — so a skipped transition is visible in the final output, not just mid-run.
Examples
Read examples.md only when slug selection or a branch outcome is unclear.
Reference formatting
Before writing any output that mentions a file, standard, section, commit, or issue, read reference-formatting.md (RFC-0001) and apply it verbatim — link files, docs, skills, agents, and sections, and never leave a reference as bare text.