Branch Config
Branch Configuration (_branch)
Section titled “Branch Configuration (_branch)”Branch detection and merge behavior, configured per-project in .claude/settings.local.json under the _branch key.
Script: ~/.claude/scripts/branch-detect.sh — single source of truth for branch resolution across all commands and hooks.
Schema
Section titled “Schema”| Field | Type | Default | Description |
|---|---|---|---|
_branch.main |
string|null | auto-detect | Override main branch name |
_branch.session |
string|null | auto-detect | Override session/working branch |
_branch.merge_strategy |
"ff-only" | "merge-commit" | "squash" |
"ff-only" |
Merge strategy for /finish-work and warp-drive |
_branch.scope |
{"area": "<slug>"} | {"flightplan": "<N>"} | absent |
none | Stream↔scope binding (#1177): the warp-drive scope bound to the session branch |
Auto-Detection (no config)
Section titled “Auto-Detection (no config)”When _branch is not set, branch-detect.sh auto-detects:
- Main branch:
origin/HEAD→ localmain→ localmaster→ error - Session branch: current branch if not on main, otherwise null
- Merge target: session branch if set, otherwise main
- Merge strategy:
ff-only
Examples
Section titled “Examples”Default (no config needed)
Section titled “Default (no config needed)”Most repos need no configuration — detection just works.
{}Output on a main-based repo while on feature/foo:
{"main":"main","session":"feature/foo","current":"feature/foo","on_main":false,"merge_target":"feature/foo","merge_strategy":"ff-only","scope":""}Explicit session branch
Section titled “Explicit session branch”Pin session branch so it persists even when on main (e.g., long-running dev branch):
{ "_branch": { "session": "dev/sprint-3" }}Stream↔scope binding (#1177)
Section titled “Stream↔scope binding (#1177)”Bind a warp-drive scope (an area workstream or a flight-plan issue) to the integration branch when opening the stream, so every kickoff in the checkout lines up with it automatically:
warp session start dev/warp-stream --area warp-drive # or: --flightplan 1078{ "_branch": { "session": "dev/warp-stream", "scope": { "area": "warp-drive" } }}The binding is enforced at /warp-drive kickoff by resolveScopeBinding() (scripts/warp-drive/kickoff.js), feeding the run’s normal session.kickoff state so scope precedence stays in kickoffScope() (#992):
- No scope flags → the kickoff defaults to the bound scope; an unscoped run on a bound stream can never reach the full approved queue.
- Explicit matching scope → passes through unchanged.
- Explicit
--issue→ allowed; a named issue is explicit operator intent strictly narrower than the binding. - Different area/plan (or mixed kinds) → refused with a message naming the bound stream and how to re-bind or end it.
Because it lives in settings.local.json, the binding survives session end, segmentation, and machine restart — and it is per-checkout, so cdfork worktrees each carry their own binding and parallel streams on different areas coexist. warp session end and warp finalize clear it together with the branch pin; to run a different scope, re-bind (warp session start <branch> --area <slug>) or end the stream first. A scope recorded without a session pin is inert.
branch-detect.sh reports the binding as a scope field ("area:<slug>" / "flightplan:<N>", empty when unbound; also via --field scope); warp session status and warp status display it omit-when-empty.
Custom main branch (develop)
Section titled “Custom main branch (develop)”For repos using develop as the integration branch:
{ "_branch": { "main": "develop" }}Squash merging
Section titled “Squash merging”For projects that prefer squash merges:
{ "_branch": { "merge_strategy": "squash" }}Merge Strategy → Git Flag Mapping
Section titled “Merge Strategy → Git Flag Mapping”| Strategy | Git flag | Behavior |
|---|---|---|
ff-only |
--ff-only |
Fast-forward only, fails if diverged |
merge-commit |
--no-ff |
Always create a merge commit |
squash |
--squash |
Squash all commits into one |
Unified freshness/finalize policy (#1178/#1179)
Section titled “Unified freshness/finalize policy (#1178/#1179)”Integration-branch streams follow one sync policy in both directions, and it never rebases:
- During the stream (kickoff, segment resume,
warp session starton an existing branch): main is merged into the stream byscripts/warp-drive/stream-freshness.sh. A pushed stream must never be rebased — rewriting shared history breaks every checkout tracking it. - At
warp finalize(L3): the stream is freshened one last time (same merge-in engine — no rebase-onto-main step), then shipped to main using the configuredmerge_strategyflag above. Because a freshened stream strictly descends from main, theff-onlydefault ships cleanly with any absorbed sync-merge commits preserved in history; setmerge-commitif you want an explicit--no-ffship commit marking the stream boundary. The policy is carried entirely bymerge_strategy— there is no hidden finalize-specific override.
When does rebase apply? Never inside warp tooling. Rebasing is acceptable only as a manual choice on a branch that has never been pushed (nothing shared to rewrite); once a stream has an upstream, merge-in is the only sync direction.
Consumer Commands
Section titled “Consumer Commands”| Command / Script | Uses |
|---|---|
/start-work |
Detects main for checkout; writes _branch.session after branch creation |
warp session start/end, warp finalize |
Write/clear _branch.session + _branch.scope (stream↔scope binding, #1177) |
kickoff.js (resolveScopeBinding) |
Applies _branch.scope at /warp-drive kickoff — bound default, conflict refusal |
/finish-work |
Detects main for rebase/merge target |
/warp-drive |
Detects main, session, merge_target, merge_strategy for all merge operations |
check-branch.sh hook |
Detects main for branch enforcement |
state-machine.js |
Stores branch fields in warp-drive state |