# Branch Create

> Create and checkout a git branch following repository naming conventions with GitHub issue integration. Use when creating branches, or when invoked from other skills.

- Skill: `awinogradov/branch-create` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add awinogradov/branch-create`
- Raw SKILL.md: https://api.skillmd.com/api/skills/awinogradov/branch-create/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: awinogradov (https://skillmd.com/u/awinogradov)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/awinogradov/branch-create

---


# 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:plan` for automatic branch creation
- When invoked from other skills

## Input

Arguments: `$ARGUMENTS`

Expected forms:

- `<ISSUE-NUMBER>` — GitHub issue number (e.g., `123` or `#123`). Used to fetch the issue and to build the branch name `issue-<number>-<slug>`.
- `<LINEAR-ID>` — Linear identifier (e.g., `ENG-123`, matching `^[A-Z]+-[0-9]+$`) when the project lists a `linear` tracker in `package.json` `agents.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 `--security` for code-scanning alert fixes → `security-<slug>`)
- `--autopilot` — non-interactive mode used by `/autopilot:run`. Skips the [Phase 0](#phase-0-preflight-check) preflight, which the calling chain already ran, and the [Phase 5](#phase-5-confirm-special-prefix-branch-name) 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](#phase-4-check-for-conflicts)) 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](#phase-3-generate-branch-slug) rules → no user prompt (auto-generate always succeeds).
- **Special prefix flags** (`--hotfix` / `--trivial` / `--maintenance` / `--proposal` / `--security`) — `$ARGUMENTS` only. Never inferred. Default: none.
- **`--autopilot`** — `$ARGUMENTS` only. Never inferred. Default: `false` (interactive mode).
- **Repository conventions** — read `CONTRIBUTING.md` directly from the repository root.

## Phase 0: Preflight Check

**Autopilot bypass:** parse `$ARGUMENTS` for `--autopilot` before anything else — the same parse [Phase 1](#phase-1-input-validation) 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](#phase-6-execute) 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).

## Phase 1: Input Validation

1. **Parse `$ARGUMENTS`** (shell-quoted positional tokens):
   - Check for `--autopilot`: if present, strip it from the arguments and set `autopilotMode = true`. Otherwise `autopilotMode = false`.
   - Check for `--start`: if present, strip it and set `startIssue = true` (Linear only; see [Phase 6](#phase-6-execute)). Otherwise `startIssue = 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 `$ARGUMENTS` is empty, fall back to Input resolution (see above).

2. **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](#phase-2-fetch-github-issue) (no GitHub issue to fetch)

3. **If no flag, validate the issue identifier and resolve the provider** (read `package.json` `agents.trackers` with the Read tool):
   - **Linear** — the identifier matches `^[A-Z]+-[0-9]+$` (e.g., `ENG-123`) AND a `linear` tracker is configured: set `provider = linear`.
   - **GitHub** — the identifier matches `^#?[0-9]+$` (strip a leading `#`): set `provider = 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`

## 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](./references/linear-branch.md#fetch-the-ticket) and follow its fetch path instead of the GitHub steps below.

1. **Determine the repository** and bind it to `REPO` so every `gh` call in this phase targets the same repo (important in worktrees and multi-remote checkouts):

   ```bash
   REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
   ```

2. **Fetch the issue** (include `assignees` so the self-assign step needs no extra call):

   ```bash
   gh issue view <ISSUE-NUMBER> -R "$REPO" --json title,body,state,assignees
   ```

3. **Extract:**
   - Issue title (for slug generation)
   - Issue body (for context)
   - Current state (warn if already closed)

4. **If issue not found:**
   - Error: `Issue #<ISSUE-NUMBER> not found in <repo>`

5. **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](#phase-2-fetch-github-issue), so they never assign). On ANY failure, emit the status line and continue to [Phase 3](#phase-3-generate-branch-slug) — 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 authenticated`
   - `unassigned — issue closed`
   - `unassigned — permission denied or assignee limit reached`
   - `unassigned — gh edit error: <first line of stderr>`

   Execution steps: read [`references/self-assign.md`](./references/self-assign.md) at this step.

## Phase 3: Generate Branch Slug

**If special prefix branch:**

1. Normalize description to lowercase kebab-case
2. Remove special characters (keep only `a-z0-9-`)
3. Construct branch name: `<prefix>-<slug>` (prefix lowercased)
4. Example: `--hotfix` + `"memory leak in editor"` → `hotfix-memory-leak-editor`; `--security` + `"tainted format string"` → `security-tainted-format-string`
5. Validate total length ≤ 100 characters — if over 60, suggest shorter description; if over 100, require it

**If custom description provided:**

1. Normalize to lowercase kebab-case
2. Remove special characters (keep only `a-z0-9-`)
3. Use as the slug

**If no description provided:**

1. Analyze issue title and body
2. Generate a short, meaningful business-focused slug
3. **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`](../shared-rules/references/askuserquestion-format.md) and apply it before composing the `question` parameter.

1. **Check local branches:**

   ```bash
   git show-ref --verify --quiet refs/heads/<branch-name>
   ```

2. **Check remote branches:**

   ```bash
   git ls-remote --heads origin <branch-name>
   ```

3. **Handle conflicts using AskUserQuestion tool:**

   If branch exists locally or remotely, present options:

   Tool parameters:
   - `question`: "Branch <branch-name> 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 <branch-name>-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](#phase-6-execute) 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](#phase-1-input-validation)), skip this entire phase and proceed directly to [Phase 6](#phase-6-execute) with the resolved branch name. Do NOT call AskUserQuestion.

For a special-prefix branch without `--autopilot`, read [special-prefix-dialog.md](./references/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`](../shared-rules/references/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](#phase-3-generate-branch-slug) 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.

1. **Fetch latest remote and create branch from origin/main:**

   ```bash
   git fetch origin
   git checkout -b <branch-name> origin/main
   ```

2. **Push with tracking:**

   ```bash
   git push -u origin <branch-name>
   ```

3. **If `provider` is `linear` AND `--start` was passed:** follow [Start the ticket](./references/linear-branch.md#start-the-ticket), then include its outcome in the result below. Skip this reference for every other branch.

4. **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 ready
   ```

   When `--start` was passed for a Linear ticket, add the step 3 outcome line after the push confirmation — `✓ Ticket <LINEAR-ID> moved to In Progress` on success, or the `issue not started — <reason>` line on failure — so a skipped transition is visible in the final output, not just mid-run.

## Examples

Read [examples.md](./references/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`](../shared-rules/references/reference-formatting.md) (RFC-0001) and apply it verbatim — link files, docs, skills, agents, and sections, and never leave a reference as bare text.

