An agent that cannot run your dev server cannot tell whether its change works. Fleet gives each session a place to run things and a set of ports that are actually its own.
Run scripts
A repository declares named scripts: dev, test, storybook. Each has a command, arguments, a
working directory relative to the worktree, an icon, and one is the default that the Run control
fires without opening its menu.
Scripts run concurrently by default. A repository can instead say non-concurrent, so starting one stops the others, which is what you want for anything that binds a port.
Two lifecycle scripts sit alongside them and stream into the same pane:
- Setup runs once, after the worktree exists and before the agent starts.
- Archive runs before the worktree is torn down, to clean up anything living outside it. It is time limited, because teardown must not hang on it.
Ports
Each session gets a deterministic block of ten consecutive ports from the range 3100 to 3999.
Deterministic matters: the block is derived from the session's identity rather than handed out by a
counter, so the same session lands on the same block after a restart and a bookmarked
localhost:3140 keeps working. Blocks are probed a whole block at a time, because a block starting
one port into another session's would hand out ports two sessions both believed they owned.
The range sits above 3000 so Fleet's blocks do not fight whatever you started by hand.
Your scripts and the agent both see the block through the environment:
FLEET_PORT the base, what a dev server should bind
FLEET_PORT1 the rest of the block
FLEET_PORT2
...
FLEET_PORT9
Ten per session rather than one, so a project can serve an app, an API and a database from a single block without inventing its own offsets.
Everything else in the environment
Every child Fleet starts in a worktree, including the agent process, sees the same variables, so
npm run dev and the agent writing a .env agree about the port:
FLEET=1
FLEET_SESSION_ID
FLEET_WORKSPACE the session title
FLEET_WORKTREE
FLEET_REPO
FLEET_BRANCH
A repository can add its own variables too. The order is fixed and it matters: the inherited
environment first, then the repository's variables, then the FLEET_* names last. A repository that
declared FLEET_PORT itself would otherwise break every script that reads it, and the failure would
look like a port collision rather than a settings mistake.
The terminal
A session also gets a real shell in its worktree, with escape sequences intact so anything that draws a progress bar draws one.
The run log is the opposite treatment of the same bytes: it strips ANSI, because it is a list of lines and the escapes would be noise. Both are right for what they are.
Stopping things properly
A run child is spawned into its own process group and stopped by signalling the whole group.
Signalling the process alone would reach npm and leave the vite it forked still running and still
holding the port, so the next start collides with a process nothing in the interface can point at.
Terminals hold their worktree open, so every shell is killed before a worktree is removed, alongside the run scripts.