---
name: workleaf
description: Creates an ephemeral sub-worktree (a "workleaf") for quick atomic work — runs its own Vite dev server, squash-merges back into the parent, then self-deletes. Use when asked to create a workleaf, spawn a workleaf, or merge/delete one.
---

# Workleaf Skill

> Triggered by: "create workleaf", "new workleaf", "spawn workleaf", "merge workleaf", "delete workleaf", "workleaf"

## What This Does

A **workleaf** is a lightweight, ephemeral sub-worktree owned by a parent
worktree (or main). Each workleaf:

- Is a real `git worktree` on its own branch (`<parent>--workleaf--<slug>`)
- Lives under `<repo-root>/workleafs/<parent>/workleaf--<slug>/`
- Runs its own Vite dev server on its own port (auto-allocated, persisted in `worktrees/ports.json`)
- Gets squash-merged back into its parent branch via `workleaf merge`
- Self-deletes after a successful merge — directory, branch, port, and dev server all reclaimed

Use a workleaf instead of a full worktree when the work is small, fast,
and should land as a single squash commit on the branch you're already
working in.

> **⚠️ Workleaves cannot be nested.** You cannot create a workleaf from
> inside another workleaf. `workleaf create` refuses with an error.

## How to Execute

All operations go through `npx storyboard workleaf <subcommand>`. The CLI
infers parent + paths from the current cwd, so you usually don't need flags.

### Create

```bash
# From main (or any worktree):
npx storyboard workleaf create [name]
```

If you omit `[name]`, an `<adjective>-<tree>` name is auto-generated
(e.g. `sunny-baobab`, `wise-ginkgo`) and checked for collisions
against existing workleaves and `<parent>--workleaf--<slug>` branches.
Pass an explicit name to skip auto-generation.

Effects:
1. Refuses if cwd is already inside a workleaf
2. Creates `<repo>/workleafs/<parent>/workleaf--<name>/` as a new git worktree
3. Branches `<parent>--workleaf--<name>` from the parent's current HEAD
4. Runs `npm install` in the workleaf
5. Allocates a port (persisted in `worktrees/ports.json`)
6. Spawns a detached `storyboard dev` and prints the URL

Flags:
- `--no-install` — skip `npm install` (fast for one-off experiments; the workleaf will reuse the parent's Node module resolution chain)
- `--no-dev` — don't start the dev server (just create the worktree)
- `--parent <name>` — override the auto-detected parent

### Merge (squash back into parent)

```bash
# From inside the workleaf:
npx storyboard workleaf merge

# Or from anywhere:
npx storyboard workleaf merge <name>
```

Effects (atomic — aborts before any change if any step fails):
1. Refuses if workleaf has uncommitted changes
2. Refuses if parent worktree is dirty or missing
3. Preflight squash probe in the parent (aborts on conflict, never leaves a MERGING state)
4. Real `git merge --squash` in the parent
5. Commits as `feat: <slug> (workleaf squash)` (override via `--message "..."` or stage-only with `--no-commit`)
6. Stops the dev server, removes the worktree, deletes the branch, releases the port

### Delete (abandon without merging)

```bash
npx storyboard workleaf delete <name>          # interactive confirm
npx storyboard workleaf delete <name> --yes    # skip confirmation
npx storyboard workleaf delete <name> --force  # discard uncommitted work too
```

Same cleanup as `merge` minus the squash + commit.

### List

```bash
npx storyboard workleaf list
```

Grouped by parent. `●` = live dev server, `○` = no server.

### cd helper

```bash
eval "$(npx storyboard workleaf cd <name>)"    # shell-aware jump
```

## Rules

- **⚠️ Folder name is `workleafs/` (plural) — NO dot prefix.** The folder
  is gitignored (`/workleafs` anchored to repo root) but intentionally
  visible.
- **⚠️ Branch name convention:** `<parent>--workleaf--<slug>`. The
  parent name is encoded in the branch so it's self-describing in
  `git branch` output.
- **⚠️ No nesting:** `workleaf create` from inside a workleaf cwd fails.
  Always `cd` to a worktree (or main) first.
- **⚠️ Parent must be clean before merge:** uncommitted changes in the
  parent worktree block `workleaf merge`. Commit or stash first.
- **Squash conflicts abort cleanly:** the preflight probe runs
  `git merge --squash` then `git reset --hard HEAD`, so the parent is
  never left in a half-merged state.
- **Workleaves are local-only by design.** If you want to push or open a
  PR, use a regular worktree via the `worktree` skill or the `ship` skill.

## When to Use a Workleaf vs Other Skills

| Need | Use |
|------|-----|
| Small fix you want as one commit on the current branch, with a fresh dev server | **workleaf** |
| Real feature branch that will be pushed and reviewed | **worktree** + commit |
| Full end-to-end shipping workflow (plan, review, push) | **ship** |
| Switch between existing worktree branches | **`storyboard branch`** |

## Notes

- Workleaves draw port assignments from the same `worktrees/ports.json`
  as regular worktrees — they coexist with worktree port reservations.
- `storyboard exit` stops every registered dev server, including
  workleaf ones (they self-register on startup).
- After a successful merge the empty parent group dir
  (`workleafs/<parent>/`) is removed too — when the last workleaf for a
  parent is gone, that whole subtree disappears.
- `detectWorktreeName()` inside the workleaf returns the full compound
  branch name, so `storyboard dev` from inside a workleaf "just works"
  and gets the workleaf's own port.
