Skip to content

Run apps side by side

Three worktrees of the same web app all want port 3000. In Offsite each worktree has its own window of 100 ports, and every app you run in it gets a port from that window. Three versions of your app run at once, and the main checkout keeps its own ports next to them.

A Run entry starts your app with $OFFSITE_PORT, the entry’s own port:

Terminal window
npm run dev -- --port $OFFSITE_PORT

Each entry keeps its port for the life of the worktree, so adding or reordering entries never moves an app that is running.

A worktree with a web app and an API gives each entry its own port, and every entry sees the others’ ports as $OFFSITE_RUN_<NAME>_PORT, the name in capitals with - as _:

Terminal window
API_URL=http://localhost:$OFFSITE_RUN_API_PORT npm run dev -- --port $OFFSITE_PORT

The web of each worktree talks to the api of the same worktree.

Each worktree's web reaches the api of its own worktree through $OFFSITE_RUN_API_PORT, so two copies of the app run side by side without crossing.

The worktree’s header has a Run button for its app; with several apps, one Run button whose popover lists them. It starts the entry in your login shell with the worktree’s environment, so nvm and other shell functions work. The popover shows its terminal and the port the app listens on, with a copy button, and offers Stop and Run again. When an app exits with an error, Ask an agent hands the failure to an agent.

When another process already listens on the port, the start goes ahead and a note names that process and its pid.

The column card shows Running, Stopped or Exited with the exit status, with the names of the apps when there are several.

A Browser card in a worktree opens the repository’s start page on the worktree’s first port, the one its first Run entry gets. With http://localhost:3000 as the start page, a worktree whose window starts at 24100 opens http://localhost:24100. Set the start page in the Browser card’s settings; see Browser.

The worktree’s agent starts apps through its worktree_run tool. They run in the same Run terminals you see in the header, on the same ports. Its brief asks it to start its own dev server, database or simulator instance for tests, to leave processes it did not start alone, and to stop what it started before it reports.

Name what a worktree creates outside its folder after its port window, and drop it in Clean up:

Terminal window
docker compose -p bloom-$OFFSITE_PORT_BASE up db

Each worktree then has its own container, and deleting the worktree removes it.

Every agent, terminal, setup step and run entry in a worktree gets:

VariableValue
OFFSITE_PORT_BASE, OFFSITE_PORT_BASE_ENDthe worktree’s port window, 100 ports between 20000 and 29999
OFFSITE_WORKTREE_PATHthe worktree’s folder
OFFSITE_WORKTREE_BRANCHits branch
OFFSITE_WORKTREE_BASE_COMMITthe commit it started from
OFFSITE_SOURCE_CHECKOUTthe main checkout

A run entry also gets:

VariableValue
OFFSITE_PORTthis entry’s port
OFFSITE_RUN_<NAME>_PORTthe port of each entry, by name
OFFSITE_RUN_NAMEthis entry’s name

The window is picked from the branch name when the worktree is created and stays with it. Offsite picks a window no other worktree or main checkout holds.

The main checkout takes its own window the first time its Setup or Run needs one. There, Setup and Run get OFFSITE_PORT_BASE, OFFSITE_PORT_BASE_END and OFFSITE_SOURCE_CHECKOUT, and each run entry its OFFSITE_PORT variables; the main checkout’s agents and terminals keep their environment as it is.