name: agent-ops-branch-workflow description: "Standardized branch creation with type detection, issue ID extraction, and worktree setup. Creates working branches (-WB) and integrates with selective-copy for clean PRs." license: MIT compatibility: [opencode, claude, cursor]
metadata: category: git related: [agent-ops-interview, agent-ops-selective-copy, agent-ops-git]
Branch Workflow — Standardized Branch Creation
Create working branches with consistent naming from task descriptions. Platform agnostic.
Works with or without aoc CLI. Uses standard git commands.
Purpose
Standardize branch creation with:
- Type detection — Auto-detect bug/feature/refactor from description
- Issue ID extraction — JIRA, GitHub, or internal issue references
- Slug generation — Short, URL-safe names from descriptions
- Worktree setup — Parallel development without branch switching
- Clean branch integration — Seamless handoff to selective-copy
CRITICAL: No Assumptions
NEVER assume. NEVER guess. ALWAYS ask.
Before creating ANY branch, confirm with user:
| If unclear about... | ASK |
|---|---|
| Task description | "What is the task? Please include issue ID if available." |
| Source branch | "Which branch should I base this on? (e.g., develop, main)" |
| Branch type | "I detected this as a [type]. Is that correct?" |
| Issue ID | "I found [ID]. Is this the correct issue reference?" |
| Generated name | "I'll create branch {name}. Does this look right?" |
If ANY of these are ambiguous:
- Stop
- Ask ONE question at a time
- Wait for explicit confirmation
- Only proceed when ALL inputs are confirmed
NEVER:
- Guess the source branch
- Assume
mainordevelopwithout asking - Create a branch without showing the user the exact name first
- Proceed if the task description is vague
Branch Naming Convention
Working branch: {type}/{ID}-{slug}-WB
Clean branch: {type}/{ID}-{slug}
Examples:
| Task | Working Branch | Clean Branch |
|---|---|---|
| "GATS-0666: Add auth support" | feature/GATS-0666-add-auth-WB | feature/GATS-0666-add-auth |
| "Fix #123 login timeout" | bugfix/123-login-timeout-WB | bugfix/123-login-timeout |
| "Refactor database layer" | refactor/db-layer-WB | refactor/db-layer |
Invocation
User says something like:
- "Create a branch for GATS-0666: Add authentication"
- "Start working on fix for login timeout bug"
- "New feature branch based on develop"
Arguments
| Argument | Description | Required | Default |
|---|---|---|---|
task_description | Description of work (for type/ID/slug detection) | Yes | - |
source_branch | Branch to base new branch on | Yes | - |
branch_name | Override auto-generated name | No | Auto-generated |
Phase 1: Create Working Branch
Step 1: Gather Requirements
If not provided, ask:
To create your working branch, I need:
1. What's the task? (include issue ID if you have one)
Example: "GATS-0666: Add OAuth2 authentication support"
2. Which branch should I base this on?
Example: develop, main, release/v2.0
Step 2: Detect Branch Type
Analyze the task description to determine type:
| Keywords | Type |
|---|---|
| hotfix, critical, urgent, emergency | hotfix/ |
| fix, bug, error, crash, broken, issue | bugfix/ |
| refactor, cleanup, restructure, reorganize | refactor/ |
| doc, readme, changelog, documentation | docs/ |
| chore, deps, dependency, maintenance, update | chore/ |
| (default) feature, add, implement, create | feature/ |
# PowerShell - Type Detection
function Get-BranchType {
param([string]$Description)
$desc = $Description.ToLower()
if ($desc -match 'hotfix|critical|urgent|emergency') { return 'hotfix' }
if ($desc -match 'fix|bug|error|crash|broken|issue') { return 'bugfix' }
if ($desc -match 'refactor|cleanup|restructure|reorganize') { return 'refactor' }
if ($desc -match 'doc|readme|changelog') { return 'docs' }
if ($desc -match 'chore|deps|dependency|maintenance|update') { return 'chore' }
return 'feature'
}
# Bash - Type Detection
get_branch_type() {
local desc="${1,,}" # lowercase
if [[ "$desc" =~ hotfix|critical|urgent|emergency ]]; then echo "hotfix"; return; fi
if [[ "$desc" =~ fix|bug|error|crash|broken|issue ]]; then echo "bugfix"; return; fi
if [[ "$desc" =~ refactor|cleanup|restructure|reorganize ]]; then echo "refactor"; return; fi
if [[ "$desc" =~ doc|readme|changelog ]]; then echo "docs"; return; fi
if [[ "$desc" =~ chore|deps|dependency|maintenance|update ]]; then echo "chore"; return; fi
echo "feature"
}
Step 3: Extract Issue ID
Look for issue identifiers in the description:
| Pattern | Example | Type |
|---|---|---|
[A-Z]{2,10}-\d+ | GATS-0666, PROJ-123 | JIRA |
#\d+ | #456 | GitHub |
[A-Z]+-\d+@\w+ | FEAT-0305@p8q9r0 | Internal |
# PowerShell - Issue ID Extraction
function Get-IssueId {
param([string]$Description)
# JIRA pattern: PROJECT-123
if ($Description -match '([A-Z]{2,10}-\d+)') {
return @{ Id = $Matches[1]; Type = 'jira' }
}
# GitHub pattern: #123
if ($Description -match '#(\d+)') {
return @{ Id = $Matches[1]; Type = 'github' }
}
# Internal AgentOps pattern
if ($Description -match '([A-Z]+-\d+)@\w+') {
return @{ Id = $Matches[1]; Type = 'internal' }
}
return @{ Id = $null; Type = 'none' }
}
# Bash - Issue ID Extraction
get_issue_id() {
local desc="$1"
# JIRA pattern
if [[ "$desc" =~ ([A-Z]{2,10}-[0-9]+) ]]; then
echo "${BASH_REMATCH[1]}"
return
fi
# GitHub pattern
if [[ "$desc" =~ \#([0-9]+) ]]; then
echo "${BASH_REMATCH[1]}"
return
fi
# Internal pattern
if [[ "$desc" =~ ([A-Z]+-[0-9]+)@ ]]; then
echo "${BASH_REMATCH[1]}"
return
fi
echo ""
}
Step 4: Generate Slug
Create a short, URL-safe name from the description:
# PowerShell - Slug Generation
function Get-BranchSlug {
param(
[string]$Description,
[string]$IssueId,
[int]$MaxLength = 30
)
$text = $Description
# Remove issue ID
if ($IssueId) {
$text = $text -replace [regex]::Escape($IssueId), ''
}
# Remove common prefixes
$text = $text -replace '^(fix|bug|feature|add|implement|create|update|refactor)[:.\s]+', ''
# Convert to lowercase, replace non-alphanumeric with dashes
$slug = ($text.ToLower() -replace '[^a-z0-9]+', '-').Trim('-')
# Truncate at word boundary
if ($slug.Length -gt $MaxLength) {
$slug = $slug.Substring(0, $MaxLength)
if ($slug.Contains('-')) {
$slug = $slug.Substring(0, $slug.LastIndexOf('-'))
}
}
if ([string]::IsNullOrEmpty($slug)) { $slug = 'work' }
return $slug
}
# Bash - Slug Generation
get_branch_slug() {
local desc="$1"
local issue_id="$2"
local max_length="${3:-30}"
local text="$desc"
# Remove issue ID
if [ -n "$issue_id" ]; then
text="${text//$issue_id/}"
fi
# Remove common prefixes
text=$(echo "$text" | sed -E 's/^(fix|bug|feature|add|implement|create|update|refactor)[:. ]+//i')
# Convert to lowercase, replace non-alphanumeric with dashes
local slug=$(echo "$text" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//;s/-$//')
# Truncate
if [ ${#slug} -gt $max_length ]; then
slug="${slug:0:$max_length}"
slug="${slug%-*}" # Remove partial word
fi
[ -z "$slug" ] && slug="work"
echo "$slug"
}
Step 5: Build Branch Name
# PowerShell
$type = Get-BranchType -Description $TaskDescription
$issueInfo = Get-IssueId -Description $TaskDescription
$slug = Get-BranchSlug -Description $TaskDescription -IssueId $issueInfo.Id
if ($BranchName) {
$workingBranch = $BranchName
} elseif ($issueInfo.Id) {
$workingBranch = "$type/$($issueInfo.Id)-$slug-WB"
} else {
$workingBranch = "$type/$slug-WB"
}
Write-Host "Branch type: $type"
Write-Host "Issue ID: $($issueInfo.Id ?? 'none')"
Write-Host "Slug: $slug"
Write-Host "Working branch: $workingBranch"
# Bash
type=$(get_branch_type "$task_description")
issue_id=$(get_issue_id "$task_description")
slug=$(get_branch_slug "$task_description" "$issue_id")
if [ -n "$branch_name" ]; then
working_branch="$branch_name"
elif [ -n "$issue_id" ]; then
working_branch="${type}/${issue_id}-${slug}-WB"
else
working_branch="${type}/${slug}-WB"
fi
echo "Branch type: $type"
echo "Issue ID: ${issue_id:-none}"
echo "Slug: $slug"
echo "Working branch: $working_branch"
Step 6: Create Worktree
# PowerShell
# Calculate worktree path (replace / with - for filesystem)
$worktreePath = "../$($workingBranch -replace '/', '-')"
# Ensure source branch exists and is up to date
git fetch origin $SourceBranch 2>$null
# Create worktree with new branch
git worktree add -b $workingBranch $worktreePath "origin/$SourceBranch"
if ($LASTEXITCODE -eq 0) {
Write-Host "`n✓ Working branch created successfully" -ForegroundColor Green
Write-Host " Branch: $workingBranch"
Write-Host " Path: $worktreePath"
Write-Host " Based on: $SourceBranch"
Write-Host "`nTo start working:"
Write-Host " cd $worktreePath"
} else {
Write-Error "Failed to create worktree"
}
# Bash
# Calculate worktree path
worktree_path="../${working_branch//\//-}"
# Ensure source branch exists and is up to date
git fetch origin "$source_branch" 2>/dev/null
# Create worktree with new branch
if git worktree add -b "$working_branch" "$worktree_path" "origin/$source_branch"; then
echo ""
echo "✓ Working branch created successfully"
echo " Branch: $working_branch"
echo " Path: $worktree_path"
echo " Based on: $source_branch"
echo ""
echo "To start working:"
echo " cd $worktree_path"
else
echo "Error: Failed to create worktree" >&2
exit 1
fi
Step 7: Update Focus State
After creating the branch, update .agent/focus.md:
# PowerShell
$cleanBranch = $workingBranch -replace '-WB$', ''
$focusUpdate = @"
## Branch Info
- working_branch: $workingBranch
- clean_branch: $cleanBranch (pending - use selective-copy)
- source_branch: $SourceBranch
- issue_id: $($issueInfo.Id ?? 'none')
- task: $TaskDescription
- worktree_path: $worktreePath
"@
# Append to focus.md or create section
Add-Content -Path ".agent/focus.md" -Value $focusUpdate
Phase 2: Create Clean Branch (for PR)
When ready for code review, use selective-copy to create the clean branch:
# PowerShell
# The clean branch is the working branch without -WB suffix
$cleanBranch = $workingBranch -replace '-WB$', ''
# Invoke selective-copy (manually or via skill)
# This will:
# 1. Create $cleanBranch from $workingBranch
# 2. Exclude .agent/, .github/, and logged files
# 3. Create exclusion log for selective-merge
User command:
Create a clean branch for PR
The selective-copy skill will:
- Detect the working branch (ends with
-WB) - Auto-generate clean branch name (remove
-WB) - Exclude agent-ops files
- Create exclusion log
Complete Workflow Example
# === PHASE 1: Start Work ===
# User: "Create a branch for GATS-0666: Add OAuth2 authentication"
# Source: develop
# Agent detects:
# - Type: feature
# - Issue ID: GATS-0666
# - Slug: oauth2-auth
# Agent creates:
git worktree add -b feature/GATS-0666-oauth2-auth-WB ../feature-GATS-0666-oauth2-auth-WB origin/develop
# === WORK HAPPENS HERE ===
# Agent assists with implementation in the worktree
# Files logged to .agent/log/created-files.log
# === PHASE 2: Ready for PR ===
# User: "Create a clean branch for PR"
# Agent invokes selective-copy:
# - source: feature/GATS-0666-oauth2-auth-WB
# - target: feature/GATS-0666-oauth2-auth
# Push for review:
cd ../feature-GATS-0666-oauth2-auth
git push origin feature/GATS-0666-oauth2-auth
# === REVIEW CYCLE ===
# After feedback, use selective-merge to sync changes
Verification
After branch creation:
# PowerShell
Write-Host "`n=== Branch Verification ===" -ForegroundColor Cyan
# List worktrees
Write-Host "`nWorktrees:"
git worktree list
# Show branch info
Write-Host "`nNew branch:"
git -C $worktreePath branch -vv
# Show files
Write-Host "`nFiles in worktree:"
Get-ChildItem $worktreePath -Name | Select-Object -First 10
# Bash
echo ""
echo "=== Branch Verification ==="
# List worktrees
echo ""
echo "Worktrees:"
git worktree list
# Show branch info
echo ""
echo "New branch:"
git -C "$worktree_path" branch -vv
# Show files
echo ""
echo "Files in worktree:"
ls "$worktree_path" | head -10
Error Handling
| Error | Cause | Solution |
|---|---|---|
| "Branch already exists" | Name collision | Append timestamp: {branch}-{yyyyMMdd} |
| "Source branch not found" | Invalid source | Run git fetch origin, verify name |
| "Worktree path exists" | Directory collision | Remove old worktree or use different path |
| "fatal: not a git repository" | Wrong directory | Navigate to git repo root |
Branch Name Collision
# PowerShell - Handle existing branch
$baseBranch = $workingBranch
$counter = 1
while (git show-ref --verify --quiet "refs/heads/$workingBranch") {
$workingBranch = "$baseBranch-$counter"
$counter++
}
Cleanup
After PR is merged:
# PowerShell
# Remove worktree
git worktree remove $worktreePath
# Delete working branch locally
git branch -d $workingBranch
# Delete clean branch locally
git branch -d $cleanBranch
# Delete remote branches (if desired)
git push origin --delete $workingBranch
git push origin --delete $cleanBranch
# Bash
# Remove worktree
git worktree remove "$worktree_path"
# Delete branches locally
git branch -d "$working_branch"
git branch -d "$clean_branch"
# Delete remote branches (if desired)
git push origin --delete "$working_branch"
git push origin --delete "$clean_branch"
Related Skills
| Skill | Relationship |
|---|---|
agent-ops-selective-copy | Creates clean branch from working branch |
agent-ops-selective-merge | Syncs working → clean after review feedback |
agent-ops-git | Underlying git operations |
agent-ops-implementation | Logs created files in working branch |