Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ The spec and tests must be kept in sync with the code.
## Branching

`main` is the primary branch. `enhs` is used for enhancement batches.

## Formatting

Markdown tables must be human-readable in a plain text editor — pad columns
with spaces so they align evenly.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ When running in a git worktree, `yolo` can detect and optionally bind mount the
- `--worktree=bind`: Automatically bind mounts the original repo
- `--worktree=skip`: Skip bind mounting and continue normally
- `--worktree=error`: Exit with error if running in a worktree
- `--worktree=create:<branch>`: Create a new worktree and branch, then launch with bind mode

```bash
# Prompt for bind mount decision (default)
Expand All @@ -50,6 +51,9 @@ yolo --worktree=skip

# Disallow running in worktrees
yolo --worktree=error

# Create an isolated worktree for an agent to work in
yolo --worktree=create:fix-issue-99
```

**Security note**: Bind mounting the original repo exposes more files and allows modifications. The prompt helps prevent unintended access.
Expand Down
58 changes: 43 additions & 15 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,17 @@ claude. If no `--` is present, all positional arguments go to claude.

### Flags

| Flag | Default | Description |
|----------------------|----------|--------------------------------------------------------------|
| `-h`, `--help` | — | Show help and exit |
| `--anonymized-paths` | off | Use `/claude` and `/workspace` instead of host paths |
| `--entrypoint=CMD` | `claude` | Override container entrypoint |
| `--entrypoint CMD` | `claude` | Same, space-separated form |
| `--worktree=MODE` | `ask` | Git worktree handling: `ask`, `bind`, `skip`, `error` |
| `--nvidia` | off | Enable NVIDIA GPU passthrough via CDI |
| `--no-config` | off | Ignore all configuration files |
| `--install-config` | — | Create or display `.git/yolo/config` template, then exit |
| Flag | Default | Description |
|------------------------------|----------|----------------------------------------------------------|
| `-h`, `--help` | — | Show help and exit |
| `--anonymized-paths` | off | Use `/claude` and `/workspace` instead of host paths |
| `--entrypoint=CMD` | `claude` | Override container entrypoint |
| `--entrypoint CMD` | `claude` | Same, space-separated form |
| `--worktree=MODE` | `ask` | Git worktree handling: `ask`, `bind`, `skip`, `error` |
| `--create-worktree=BRANCH` | — | Create or resume a worktree (see §5) |
| `--nvidia` | off | Enable NVIDIA GPU passthrough via CDI |
| `--no-config` | off | Ignore all configuration files |
| `--install-config` | — | Create or display `.git/yolo/config` template, then exit |

### Argument Routing

Expand Down Expand Up @@ -80,11 +81,12 @@ User-wide and project arrays are concatenated (user-wide first).

#### Scalars (project overrides user-wide; CLI overrides both)

| Key | Type | Default | Description |
|------------------------|----------|---------|--------------------------------|
| `USE_ANONYMIZED_PATHS` | `0\|1` | `0` | Use anonymized container paths |
| `USE_NVIDIA` | `0\|1` | `0` | Enable NVIDIA GPU passthrough |
| `WORKTREE_MODE` | `string` | `ask` | Git worktree handling mode |
| Key | Type | Default | Description |
|------------------------|----------|---------------------|--------------------------------------------|
| `USE_ANONYMIZED_PATHS` | `0\|1` | `0` | Use anonymized container paths |
| `USE_NVIDIA` | `0\|1` | `0` | Enable NVIDIA GPU passthrough |
| `WORKTREE_MODE` | `string` | `ask` | Git worktree handling mode |
| `WORKTREE_DIR` | `string` | `.git/my-worktrees` | Worktree directory (relative to repo root) |

### Loading Order

Expand Down Expand Up @@ -176,6 +178,32 @@ All projects appear at `/workspace`, enabling cross-project session context.

When mounted, the original repo is bind-mounted at its host path with `:z`.

### Creation (`--create-worktree`)

Syntax: `--create-worktree=<branch>` or `--create-worktree=<base>:<branch>`.

| Form | Base ref | New branch |
|-------------------|----------|--------------|
| `feature-x` | HEAD | `feature-x` |
| `main:feature-x` | `main` | `feature-x` |

Bare `--create-worktree` (no value) is an error.

#### Behavior

1. If `WORKTREE_DIR/<branch>` exists on disk, `cd` into it (resume).
2. Otherwise, create via `git worktree add WORKTREE_DIR/<branch> -b <branch> [<base>]`.
3. If `<branch>` exists as a git branch but not as a worktree, exit with error.
4. After `cd`, normal worktree detection and `--worktree` mode handling applies.

### Worktree Directory

| Key | Default | Description |
|----------------|---------------------|------------------------------------------|
| `WORKTREE_DIR` | `.git/my-worktrees` | Worktree location, relative to repo root |

Only relative paths are supported.

---

## 6. Container Naming
Expand Down
25 changes: 22 additions & 3 deletions bin/yolo
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ OPTIONS:
--anonymized-paths Use anonymized paths (/claude, /workspace) instead of
preserving host paths
--entrypoint=CMD Override the container entrypoint (default: claude)
--worktree=MODE Git worktree handling: ask, bind, skip, error
--worktree=MODE Git worktree handling: ask, bind, skip, error,
create:<branch-name>
(default: ask)
--nvidia Enable NVIDIA GPU passthrough via CDI
Requires nvidia-container-toolkit on host
Expand Down Expand Up @@ -210,9 +211,9 @@ while [ $# -gt 0 ]; do
--worktree=*)
WORKTREE_MODE="${1#--worktree=}"
# Validate worktree mode
if [[ ! "$WORKTREE_MODE" =~ ^(ask|bind|skip|error)$ ]]; then
if [[ ! "$WORKTREE_MODE" =~ ^(ask|bind|skip|error|create(:.+)?)$ ]]; then
echo "Error: Invalid --worktree value: $WORKTREE_MODE" >&2
echo "Valid values are: ask, bind, skip, error" >&2
echo "Valid values are: ask, bind, skip, error, create:<branch-name>" >&2
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what/how to just start/resume an existing? I wonder if overall it should be a separate option whenever this one in particular about binding -- so it could be (potentially) be used with "create" as "create but do not bind original" if I want to work in better isolation. So -- orthogonal features, and thus potentially orthogonal options desired IMHO.

Also as I have mentioned, might be worth right away to think about sub-agents and worktrees WITHIN claude session. If isolated, I guess we want to keep worktrees under .git/ of the main repo (where worktrees point to), but then since that one already has .git/worktrees/ (containing just .git/ level per each branch/worktree) -- we would need smth like .git/yolotrees or .git/yolo-worktrees?

exit 1
fi
shift
Expand Down Expand Up @@ -342,6 +343,24 @@ CLAUDE_HOME_DIR="$HOME/.claude"
# must exist but might not if first start on that box
mkdir -p "$CLAUDE_HOME_DIR"

# Handle --worktree=create:<branch-name>: create a new worktree and cd into it
if [[ "$WORKTREE_MODE" == "create" ]]; then
echo "Error: --worktree=create requires a branch name, e.g. --worktree=create:fix-issue-99" >&2
exit 1
elif [[ "$WORKTREE_MODE" =~ ^create:(.+)$ ]]; then
create_branch="${BASH_REMATCH[1]}"
worktree_dir="$(dirname "$(pwd)")/$create_branch"

echo "Creating worktree at $worktree_dir (branch: $create_branch)..." >&2
git worktree add "$worktree_dir" -b "$create_branch" || exit 1
cd "$worktree_dir" || exit 1

# Regenerate container name for the new directory
name=$( echo "$PWD-$$" | sed -e "s,^$HOME/,,g" -e "s,[^a-zA-Z0-9_.-],_,g" -e "s,^[._]*,," )

WORKTREE_MODE="bind"
fi

# Detect if we're in a git worktree and find the original repo
WORKTREE_MOUNTS=()
gitdir_path=""
Expand Down
2 changes: 1 addition & 1 deletion config.example
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ YOLO_CLAUDE_ARGS=(
# Enable NVIDIA GPU passthrough by default (requires nvidia-container-toolkit)
# USE_NVIDIA=0

# Git worktree handling mode: ask (default), bind, skip, or error
# Git worktree handling mode: ask (default), bind, skip, error, or create:<branch>
# WORKTREE_MODE="ask"

# ============================================================================
Expand Down
12 changes: 12 additions & 0 deletions tests/yolo.bats
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ EOF
assert_output --partial "Invalid --worktree value"
}

@test "--worktree=create: bare create exits with error" {
run_yolo --worktree=create
assert_failure
assert_output --partial "requires a branch name"
}

@test "--worktree=create:branch: passes validation" {
run_yolo --worktree=create:test-branch
# Will fail at git worktree add (not a real repo), but should NOT fail validation
refute_output --partial "Invalid --worktree value"
}

# ── Separator (--) and argument routing ───────────────────────────

@test "separator: args after -- become claude container args" {
Expand Down
Loading