```skill
---
name: create-branch
description: Git branch naming convention and creation workflow — handles working tree state, default branch detection, and interactive cleanup before branching.
---

# Create Branch

## Just-In-Time Invocation

Use this skill as the just-in-time mutation gate before the first code-writing step.
Do not treat this skill as a mandatory startup blocker for read-only startup analysis or planning.
Run this skill after the task graph is known and before the first task-executor launch.

## Branch Naming Convention

Format: `{type}/{jira}_{slug}`

- `{type}` — work type: `feature`, `fix`, `chore`
- `{jira}` — JIRA ticket ID (e.g., `CACTUS-1234`)
- `{slug}` — 3-word snake_case descriptor

Examples:
- `feature/CACTUS-1234_add_user_authentication`
- `fix/PROJ-567_fix_login_button`
- `chore/CACTUS-890_update_dependencies`

## Default Branch Detection

Detect the default branch name:
```sh
git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@'
```
Fallback: check if `master` exists, else `main`. Store as `{default_branch}`.

## Git State Initialization

Run these checks BEFORE creating a branch:

### 1. Get Current State

```sh
CURRENT_BRANCH=$(git branch --show-current)
IS_DIRTY=$(git status --porcelain)
```

Collect changed paths (staged, unstaged, untracked) and classify whether the dirty tree is documentation-only:

```sh
CHANGED_FILES=$(
	{
		git diff --name-only
		git diff --cached --name-only
		git ls-files --others --exclude-standard
	} | sed '/^$/d' | sort -u
)

NON_DOC_FILES=$(printf '%s\n' "$CHANGED_FILES" | grep -Ev '^(docs/|.*\.md$|docs/docs_cache_state\.yaml$)' || true)

DOCS_ONLY_DIRTY=false
if [ -n "$CHANGED_FILES" ] && [ -z "$NON_DOC_FILES" ]; then
	DOCS_ONLY_DIRTY=true
fi
```

### 2. Handle State Matrix

| Current Branch | Working Tree | Action |
|---------------|--------------|--------|
| `{default_branch}` | Clean | `git pull` → create branch |
| `{default_branch}` | Dirty (docs-only) | Auto-stash docs → `git pull` → create branch → `git stash pop` |
| `{default_branch}` | Dirty (non-doc or mixed) | Ask user → handle → `git pull` → create branch |
| Other branch | Clean | `git checkout {default_branch}` → `git pull` → create branch |
| Other branch | Dirty (docs-only) | Auto-stash docs → `git checkout {default_branch}` → `git pull` → create branch → `git stash pop` |
| Other branch | Dirty (non-doc or mixed) | Ask user → handle → `git checkout {default_branch}` → `git pull` → create branch |

### 3. Documentation-Only Dirty Tree (Automatic Path)

If the working tree is dirty and `DOCS_ONLY_DIRTY=true`, do not prompt the user.

1. `git stash push -u -m "WIP: docs-only auto-stash before {jira}"`
2. Continue normal branch setup (`checkout {default_branch}` when needed, `git pull`, then create/switch target branch)
3. `git stash pop`

If `git stash pop` reports conflicts, stop and ask the user how to resolve the conflict before continuing.

### 3. Dirty Working Tree Options

When dirty and the changes are non-doc or mixed, present these options to the user (use `ask_questions` tool):

- **Stash changes**: `git stash push -m "WIP: auto-stash before {jira}"` — saves changes for later
- **Discard changes**: `git checkout -- . && git clean -fd` — permanently removes uncommitted changes
- **Abort**: Stop the workflow — user handles git state manually

After stashing or discarding, working tree is clean. Proceed with checkout/pull.

## Branch Creation

After git state is clean and on `{default_branch}` with latest pulled:

```sh
# Check if branch already exists locally
git branch --list "{type}/{jira}_{slug}"

# Check if branch exists on remote
git ls-remote --heads origin "{type}/{jira}_{slug}"
```

- **Does not exist**: `git checkout -b {type}/{jira}_{slug}`
- **Exists locally**: `git checkout {type}/{jira}_{slug}`
- **Exists only on remote**: `git checkout -b {type}/{jira}_{slug} origin/{type}/{jira}_{slug}`
```
