---
id: "5.14"
title: "Parallel sessions"
dept: engineering
status: draft
owner: Param
branded: false
last_verified: 2026-10-26
sources:
  - "brew origin/main: CLAUDE.md 'Release rhythm'; deploy.sh:7, 11-16; tools/promote.sh:28-38"
  - "memory brew-parallel-sessions-deploy, brew-qa-sweep-2026-10-19, brew-community-seat, brew-move-freshness, brew-one-stage, brew-qa-round2-2026-10-24, brew-v1-creative-stage, brew-jam-v2, brew-arata-rewrite-2026-10-15, brew-read-stream-backfill, brew-shopify-app-review, brew-team-jams"
---

# Parallel sessions

## Answer

Several Claude sessions edit and deploy brew at the same time, so each one commits only its own lines, pushes to origin/main before deploying, and deploys from a clean detached worktree of origin/main; this page is the runbook that stops one session from shipping or erasing another's work.

## Today

### What went wrong before

| Date | What happened | Lesson | Source |
|---|---|---|---|
| 16 Oct | A commit of `public/app.js` swept in another session's half-done Slack and menu code | Check `git diff <file>` before adding; stage only your hunks | [src: memory brew-parallel-sessions-deploy] |
| 16 Oct | Four local-only commits were skipped by two deploys from origin's older HEAD | Push, or your commits never ship | same |
| 19 Oct | A hunk-filtered commit put a click listener inside the wrong function | Build the staged file from `git show HEAD:<file>`; check `git diff --cached` | same |
| 19 Oct | A deploy from a local main without pushed fixes dropped them from live | Deploy from a fresh worktree of origin/main; check the served `app.js?v=` hash | [src: memory brew-qa-sweep-2026-10-19] [src: memory brew-community-seat] |
| 15 Oct, 23 Oct, 24 Oct | Deploys every few minutes cut a paid rewrite, a 4-slide carousel and a read stream | Paid runs resume and save progress; before a long paid run, expect deploy churn | [src: memory brew-arata-rewrite-2026-10-15] [src: memory brew-v1-creative-stage] [src: memory brew-read-stream-backfill] |
| 24 Oct, 25 Oct | Editing a worktree while `./deploy.sh` ran from it; editing `promote.sh` while it ran | Never edit a tree or script that is deploying | [src: memory brew-qa-round2-2026-10-24] [src: memory brew-prod-backend] |
| | A rebase by another session dropped a hunk | After any rebase, check HEAD still has your lines | [src: memory brew-move-freshness] |

### What the code does to help

- `deploy.sh` refuses a dirty tree and retries the suite once, because two suites side by side can trip each other. [src: brew/deploy.sh:7, 11-16]
- Background work survives a deploy: SIGTERM leaves runs unfinished and the next instance resumes them. [src: brew/CLAUDE.md]
- One promote at a time through a lock in `gs://brew-prod-backups/locks/`. [src: brew/tools/promote.sh:28-38]
- Revisions carry a `git-sha` label. [src: brew/deploy.sh:41]

## Tomorrow

| Item | Version | Tag |
|---|---|---|
| Commit only your own lines, push, deploy from origin/main | v1 | Stays |
| A branch per session with a pull request into main | v2 | New, once Sai and Arvind code daily |
| CI on main so a broken push is seen before anyone deploys it | v1 | New |
| A shared "who is deploying" note | v2 | New |

## How we do it

1. Before adding a file, look at its diff. If another session has hunks in it, stage only yours:

```bash
git -C brew diff <file>
git -C brew show HEAD:<file> > $TMPDIR/f && <apply your edit to $TMPDIR/f>
git -C brew update-index --cacheinfo 100644,$(git -C brew hash-object -w $TMPDIR/f),<file>
git -C brew diff --cached <file>
```

2. Commit, rebase and push before deploying:

```bash
git -C brew pull --rebase && git -C brew push origin HEAD:main
```

3. Deploy from a detached worktree of origin/main, with node_modules and the brand folder linked:

```bash
git -C brew fetch origin
git -C brew worktree add --detach $TMPDIR/brew-deploy origin/main
ln -s /Users/param/Documents/ChatGPT/brew/node_modules $TMPDIR/brew-deploy/node_modules
cd $TMPDIR/brew-deploy && BRANDS_DIR=/Users/param/Documents/ChatGPT/brew/.brands ./deploy.sh
git -C /Users/param/Documents/ChatGPT/brew worktree remove $TMPDIR/brew-deploy
```

[src: memory brew-parallel-sessions-deploy] A fresh worktree may lack modules other branches added (for example `pg`, `sharp`); link the right node_modules. [src: memory brew-one-stage] [src: memory brew-jam-v2]

4. Confirm on the live site by grepping the served `app.js` for a new identifier, and check the revision's `git-sha` descends from your commit. [src: memory brew-qa-sweep-2026-10-19]
5. Never stash, reset or overwrite another session's work. [src: memory brew-parallel-sessions-deploy]
6. When a live-only bug cannot be reproduced locally, diff the served file against your working copy first. [src: memory brew-parallel-sessions-deploy]

## Numbers

| Metric | Definition | Where measured |
|---|---|---|
| Lost-commit incidents | Deploys that shipped without a pushed commit | Proposed: compare each revision's git-sha to origin/main |
| Deploys cutting paid runs | Paid runs resumed after a restart | `[build]` and `[finals]` resume logs |

## Open

1. **Should sessions move to branches and pull requests now?** Proposal: yes for any change over 200 lines; small fixes stay on main.
2. **Should long paid runs block deploys?** Proposal: no; keep resumable runs and never re-add a deploy wait.
