---
name: "exp-start"
description: "Create or join an experiment branch. Experiments run on short-lived `exp/<slug>` branches in a dedicated worktree. They never merge to `main` and neve"
---

# exp-start command

Apply this command workflow. Treat any text after its invocation as the command input.

Create or join an experiment branch. Experiments run on short-lived `exp/<slug>` branches in a dedicated worktree. They never merge to `main` and never get PRs or issues. Keepers are distilled onto `gh-*` branches via `/gh-issue-push` + `/gh-issue-pop`.

Two modes:

- **Local-only** (default): the experiment lives entirely on this repository's `origin`.
- **Remote-backed** (`--remote`): the experiment additionally syncs two ways with a separate repository through `git subtree` — remote content lives under a deterministic prefix inside the experiment branch, and local changes to that prefix can be pushed back.

## Input

$ARGUMENTS

Syntax: `<slug> [--remote <url-or-owner/repo>] [--branch <upstream-branch>] [--prefix <path>]`

The slug is kebab-case (e.g. `transformer-perf`). `--remote` accepts a full Git URL or `owner/repo` shorthand (normalized to `https://github.com/owner/repo.git`). `--branch` names the upstream branch to sync with (default: the remote's default branch). `--prefix` sets the subtree path (default: `experiments/<slug>`). If no slug is given, ask the user for one.

## Phase 1 -- Validate

1. Validate the slug is kebab-case (`[a-z0-9]+(-[a-z0-9]+)*`). Reject anything else.
2. If `--remote` is given, normalize it: `owner/repo` becomes `https://github.com/owner/repo.git`; URLs pass through. Record `REMOTE_URL`.
3. Confirm we are in the main repo directory, not inside a worktree, and the current branch is `main`:
   ```bash
   git branch --show-current
   ```
   If not on `main`, warn the user and stop. Experiment branches are created from the main repo only.

## Phase 2 -- Create or Join

1. Fetch from origin:
   ```bash
   git fetch origin
   ```

2. Check whether `origin/exp/<slug>` already exists:
   ```bash
   git ls-remote --heads origin exp/<slug>
   ```

### If the remote branch exists (join)

3a. Create a worktree tracking the branch:
   ```bash
   git worktree add ../exp-<slug> exp/<slug>
   ```

4a. If the worktree contains `.exp-sync.yaml`, this is a remote-backed experiment: read it and reconstruct the sync remote on this machine (Phase 3 step 2, using the file's `remote_name` and `remote_url`). Report that you joined an existing experiment and print the sync commands from Phase 4.

### If the remote branch does not exist (create)

3b. Create a worktree with a new branch:
   ```bash
   git worktree add ../exp-<slug> -b exp/<slug>
   ```

4b. Initialize beads inside the worktree:
   ```bash
   cd ../exp-<slug>
   bd init
   ```

5b. Commit the initial state:
   ```bash
   cd ../exp-<slug>
   git add -A
   git commit -m "exp/<slug>: initialize experiment

   Skill: exp-start
   Called-by: user"
   ```

6b. Push the branch:
   ```bash
   git push -u origin exp/<slug>
   ```

If `--remote` was given, continue to Phase 3. Otherwise skip to Phase 5.

## Phase 3 -- Remote-Backed Setup (only with --remote)

All commands run inside the worktree at `../exp-<slug>`.

1. Determine the upstream branch. If `--branch` was given, use it. Otherwise detect the remote's default branch:
   ```bash
   git ls-remote --symref <REMOTE_URL> HEAD | sed -n 's|^ref: refs/heads/\(.*\)\tHEAD|\1|p'
   ```
   Record `UPSTREAM_BRANCH`.

2. Add the sync remote under a deterministic name and fetch it:
   ```bash
   git remote add exp-<slug>-remote <REMOTE_URL> 2>/dev/null || true
   git fetch exp-<slug>-remote
   ```

3. Add the subtree under the prefix (default `experiments/<slug>`):
   ```bash
   git subtree add --prefix=<prefix> exp-<slug>-remote <UPSTREAM_BRANCH> --squash
   ```

4. Record the sync metadata so any machine can rejoin and continue syncing. Write `.exp-sync.yaml` at the worktree root:
   ```yaml
   slug: <slug>
   remote_name: exp-<slug>-remote
   remote_url: <REMOTE_URL>
   upstream_branch: <UPSTREAM_BRANCH>
   prefix: <prefix>
   push_branch: exp/<slug>
   ```
   The `push_branch` is the branch created **in the remote repository** when local subtree changes are pushed back; it follows the same never-merge convention there.

5. Commit and push the metadata and initial subtree state:
   ```bash
   git add .exp-sync.yaml
   git commit -m "exp/<slug>: configure subtree sync with <REMOTE_URL>

   Skill: exp-start
   Called-by: user"
   git push
   ```

## Phase 4 -- Ongoing Two-Way Sync (remote-backed)

Subtree operations always name the remote and branch explicitly, so plain `git push`/`git pull` stay unambiguous: they talk only to this repository's `origin` and the `exp/<slug>` branch, never to the sync remote.

Pull remote updates into the prefix:

```bash
cd ../exp-<slug>
git fetch exp-<slug>-remote
git subtree pull --prefix=<prefix> exp-<slug>-remote <UPSTREAM_BRANCH> --squash
git push   # share the merged state on origin exp/<slug>
```

Push local subtree changes back to the remote repository:

```bash
cd ../exp-<slug>
git subtree push --prefix=<prefix> exp-<slug>-remote exp/<slug>
```

This creates or updates branch `exp/<slug>` in the remote repository. It never touches the remote's default branch; landing changes there is the remote repo's own review flow, out of scope here.

## Phase 5 -- Report

Print the worktree path and the convention reminders:

```
Experiment ready at ../exp-<slug> (branch exp/<slug>).
<if remote-backed:>
Syncing with <REMOTE_URL> (<UPSTREAM_BRANCH>) under <prefix>/.
  pull:  git subtree pull --prefix=<prefix> exp-<slug>-remote <UPSTREAM_BRANCH> --squash
  push:  git subtree push --prefix=<prefix> exp-<slug>-remote exp/<slug>

Reminders:
- Never merge exp/* to main. Never open a PR or GitHub issue from it.
- Treat every push as potentially permanent — no secrets or sensitive data.
  Remote-backed: subtree pushes land in the OTHER repository and survive
  local cleanup.
- To keep a result, distill it onto a gh-* branch via /gh-issue-push + /gh-issue-pop.
- To conclude the experiment, run /exp-stop <slug>.
- On other machines, run /exp-start <slug> to join this experiment
  (remote-backed sync reconstructs itself from .exp-sync.yaml).
```
