# APP-3709: Auto-Generate Worktree Branch Names Linear: [APP-3709](https://linear.app/warpdotdev/issue/APP-3709/auto-generate-worktree-branch-names) ## Summary Replace the placeholder counter-based worktree branch name generator (`worktree-1`, `worktree-2`, …) with a pure function that produces memorable, distinctive names by combining two randomly selected desert/southwest-themed words. ## Problem The current `generate_worktree_branch_name()` function uses a global `AtomicU32` counter that: - Produces forgettable, indistinct names (`worktree-1`, `worktree-2`, …). - Resets to 1 on every app restart, so the same names get reused across sessions. - Gives no hint about which worktree is which when the user has several open. Developers often have multiple worktrees active simultaneously. Names like `mesa-coyote` or `obsidian-monsoon` are immediately distinguishable in a tab bar, branch list, or terminal prompt. ## Goals - Provide a pure, stateless function that returns a random `{word1}-{word2}` branch name drawn from a curated 198-word desert/southwest vocabulary. - Use this function everywhere a worktree branch name is auto-generated: 1. The "New worktree" modal when the "Autogenerate worktree branch name" checkbox is checked. 2. When a saved worktree tab config with `worktree_name_autogenerated = true` is re-opened from the menu. - Produce names that are valid git branch names with no further sanitization. - Guarantee uniqueness: never generate a name that collides with an existing local branch in the target repository. ## Non-goals - Letting the user configure or extend the word list. - Changing any UI layout or modal behavior — this is purely a naming-function replacement. - Persisting a "used names" set across sessions (uniqueness is checked against the repo's actual branch list at generation time). ## Figma Figma: none (no UI changes). ## User Experience ### Generated name format Each auto-generated name is two words joined by a hyphen: ``` {word1}-{word2} ``` Both words are drawn uniformly at random from the same 198-word list. The two words must be distinct (no `mesa-mesa`). Examples: `mesa-coyote`, `obsidian-monsoon`, `saguaro-twilight`, `rimrock-falcon`, `turquoise-arroyo`. ### Word list 198 words across six categories, embedded as a compile-time constant array. **Landforms & Terrain (50)** mesa, canyon, arroyo, butte, gulch, plateau, dune, bluff, ridge, ravine, basin, crater, ledge, outcrop, escarpment, badlands, flats, playa, wash, gorge, pinnacle, spire, monolith, arch, chasm, chimney, crag, cuesta, alcove, saddle, rimrock, talus, scree, coulee, caldera, cinder, lava, malpais, pediment, bajada, bolson, inselberg, tepui, mogote, notch, gap, pass, switchback, hogback, caprock **Desert Plants (35)** cactus, saguaro, agave, yucca, mesquite, ocotillo, creosote, juniper, pinyon, prickly, cholla, barrel, palo-verde, ironwood, saltbush, brittlebush, lupine, mallow, mariposa, sotol, lechuguilla, candelilla, jojoba, chamisa, rabbitbrush, claret, hedgehog, fishhook, organ-pipe, joshua, tumbleweed, sagebrush, chaparral, manzanita, madrone **Desert Animals (36)** armadillo, coyote, roadrunner, jackrabbit, rattler, sidewinder, gila, javelina, pronghorn, bighorn, kit-fox, bobcat, cougar, hawk, vulture, falcon, quail, wren, thrasher, horned-toad, gecko, tortoise, tarantula, scorpion, centipede, kingsnake, coachwhip, racer, ringtail, badger, cottontail, mule-deer, prairie-dog, burrowing-owl, nighthawk, swift **Minerals obsidian, flint, granite, quartz, sandstone, limestone, basalt, turquoise, onyx, jasper, agate, garnet, topaz, copper, iron, cobalt, tin, zinc, mica, feldspar, gypsum, calcite, shale, pumice, travertine, petrified, opal, malachite, pyrite, cinnabar **Southwest Culture & Spanish (24)** adobe, oz, tinaja, acequia, ramada, portal, ristra, luminaria, mirador, hacienda, viga, latilla, nicho, olla, metate, petroglyph, pictograph, solstice, equinox, siesta, sierra, rio, tierra, cumbre **Weather & Sky (23)** monsoon, dust-devil, mirage, sundowner, zephyr, thermal, drought, flash-flood, dry-lightning, haze, shimmer, sundog, corona, twilight, dusk, dawn, starlight, moonrise, ember, smoke, wildfire, brushfire, firestorm ### Where the function is called 1. **New worktree modal** (`new_worktree_modal.rs`): When the user clicks "Open" with the "Autogenerate worktree branch name" checkbox checked, the function is called to produce the branch name for the `git worktree add` command. 2. **Saved worktree tab configs**: When a tab config with `worktree_name_autogenerated = true` on any pane is opened from the menu, the commands' branch-name placeholder is replaced with a freshly generated name so each re-open creates a new worktree. ### Uniqueness guarantee The generated name must not collide with any existing local branch in the target repository. The function takes the repo path as input and queries the repo's branch list. On collision, it makes up to 2 attempts at the same word count before escalating to more words: 1. Generate a 2-word name (`mesa-coyote`). Up to 2 attempts if taken. 2. If both 2-word attempts collide, generate a 3-word name (`mesa-coyote-obsidian`). Up to 2 attempts. 3. Continue escalating (4 words, up to 5 words max) as needed. Each additional word exponentially increases the pool of candidates, making exhaustion effectively impossible. If the repo path is unavailable or the branch list cannot be read (e.g. not a git repo), the function falls back to generating a name without the uniqueness check — the user will see a git error if a collision occurs and can retry. ### Function properties - **Pure naming core**: The naming function takes a set of existing branch names and returns a name — no I/O. Branch listing is performed by the caller. - **Stateless**: Uses `rand` for randomness rather than a global counter. - **Git-safe output**: Every word in the list is already a valid git ref component (lowercase alphanumeric and hyphens only, no leading/trailing hyphens, no consecutive dots or slashes). ## Edge Cases 1. **Hyphenated words**: Words like `palo-verde`, `kit-fox`, `dust-devil` already contain hyphens. A name like `palo-verde-kit-fox` is valid for git and reads naturally. 2. **Deterministic testing**: The function should accept an optional random source so unit tests can assert specific outputs. 3. **Repo with many themed branches**: A user who has generated hundreds of worktrees in the same repo will still have tens of thousands of available pairs. The retry loop handles this transparently. 4. **Non-git directory**: When the repo path doesn't point to a valid git repo, skip the uniqueness check and return a random name. Git will report the error when the worktree command runs. ## Success Criteria 1. `generate_worktree_branch_name()` returns a string matching the pattern `{word}-{word}` where both words come from the 198-word list and are not the same word. 2. Repeated calls produce different names (with overwhelming probability). 3. The generated name does not collide with any existing local branch in the target repository when a repo path is provided. 4. The generated name is used as the branch name in `git worktree add -b {name}` and as the worktree directory name. 5. No global counter or shared mutable state — the function is safe to call from any thread. 6. All 198 words in the list are valid git branch name components. 7. Saved worktree configs with `worktree_name_autogenerated = true` produce a fresh name on each menu open, not the baked-in name from the TOML. ## Validation - **Unit tests**: Call the function many times, assert format matches `{word}-{word}`, assert both words are in the word list, assert the two words differ. - **Deterministic test**: Seed the random source and assert a specific output. - **Uniqueness test**: Mock a set of existing branches, call the function, assert it avoids all of them. - **Manual test**: Open the "New worktree" modal with autogenerate checked, click "Open" several times — each tab should have a distinct desert-themed branch name visible in the tab title and terminal output. - **Re-open test**: Save a worktree config, re-open it from the menu — the new tab should use a freshly generated branch name, not the one from the first open. ## Open Questions (None outstanding.)