Skip to main content

Ports & URLs

Every worktree gets a stable slot, and every configured service port is base_port + slot. The default worktree holds slot 0, so a service with base_port = 4200 listens on 4200 in the default worktree, 4201 in the first branch worktree, and so on. Slots — and therefore ports and URLs — stay stable for the life of a worktree.

Caddy Routing Is Machine-Global

Bonsai maintains a single Caddy config at ~/.bonsai/Caddyfile with per-app snippet directories at ~/.bonsai/caddy.d/<app>/, so multiple Bonsai projects coexist and all their .localhost URLs work simultaneously. Routes survive reboot via a managed block Bonsai keeps in Homebrew's boot config ($(brew --prefix)/etc/Caddyfile).

Project names must be unique per machine — two projects sharing the same name will collide on hostnames and snippet paths.

When Caddy is not installed, Bonsai falls back to direct http://localhost:<port> URLs. Both forms are expected and work fine.

Open a Worktree URL

bonsai open
bonsai open ma-123-implement-auth
bonsai open ma-123-implement-auth --service api

Run open from inside a worktree to open that worktree's primary local URL in your default browser. Pass a branch name, worktree directory, or slug to open a different worktree, and --service <name> to open a non-primary public service URL such as an API route.

By default open confirms the URL responds before launching the browser; pass --no-interactive to print the resolved URL without probing.

With a [browser_extension] extension_id configured (see Configuration), bonsai open --label "Feature tab" opens the URL through the browser extension with a labeled tab.

Diagnose URLs

bonsai urls
bonsai urls ma-123-implement-auth --service api
bonsai urls --diagnose https://api-ma-123-implement-auth.my-app.localhost
bonsai urls --format json

urls prints configured public service URLs with route diagnostics: the global Caddyfile, the per-worktree snippet, Caddy validation, app listener, TLS, and local CA trust guidance. Filter by worktree or --service, or use --diagnose <url> when a specific URL is not working.

Inspect Port Ownership

bonsai ports
bonsai ports --format json
bonsai ports --busy

ports prints every configured service port with listener ownership metadata from lsof when available. Each port is classified as free, owned by the matching worktree, conflict with another process or worktree, or unknown when the port is listening but the owner cannot be identified. ports --busy shows the same data filtered to ports with listeners.

When a branch worktree's ports conflict, bonsai repair-ports proposes a conflict-free slot — see Troubleshooting.