feat(server): configure workspace service port allocation (#2165)

* starr

* fix(server): honor service port allocator contracts

* fix(server): pass workspace context to port scripts

* fix(server): cancel released service port plans

* test(server): support Windows port allocator fixtures

* docs(worktrees): clarify shell-less portScript execution
This commit is contained in:
Matt Cowger
2026-07-20 20:50:01 +02:00
committed by GitHub
parent 2ead7e7719
commit 9292f58896
14 changed files with 738 additions and 15 deletions
+43
View File
@@ -146,6 +146,49 @@ Commands run with the worktree as `cwd`. Use `$PASEO_SOURCE_CHECKOUT_PATH` to re
Omit `port` to let Paseo auto-assign one. Bind your process to `$PASEO_PORT` rather than hard-coding, each worktree gets a distinct port so multiple copies of the same service coexist.
### Dynamic port allocation
By default, Paseo asks the OS for an available ephemeral port. Configure a range globally in
`~/.paseo/config.json` or per project in `paseo.json`:
```json
// ~/.paseo/config.json
{
"worktrees": {
"servicePorts": { "range": "3000-4000" }
}
}
```
```json
// paseo.json
{
"worktree": {
"servicePorts": { "range": "3000-4000" }
}
}
```
The range is inclusive. A project `servicePorts` block replaces the global block. An explicit
service `port` always wins over either setting.
For an external allocator, configure `portScript` instead:
```json
{
"worktree": {
"servicePorts": { "portScript": "/usr/bin/portmake" }
}
}
```
Paseo runs the executable in the workspace directory with four arguments: service name, workspace
ID, branch name, and worktree path. Since the script is executed directly without a shell, `portScript` must point to a real executable (such as a compiled binary or a script with a proper shebang line like `#!/bin/bash`) rather than an inline shell command or pipeline. If you need shell evaluation or pipelines, wrap them in a small executable script. A missing branch is passed as an empty string. The same values
are available as `PASEO_SCRIPTNAME`, `PASEO_WORKSPACE_ID`, `PASEO_BRANCH_NAME`, and
`PASEO_WORKTREE_PATH`. It must print one valid TCP port to stdout. `portScript` wins over `range` in
the same block. Paseo trusts the external allocator, so the returned port may already be in use, for
example by a service Paseo will attach to.
### Reverse proxy
Every service is reachable through the daemon at a deterministic hostname: