Skip to Content
GuidesDev server & ports

Dev server & ports

Every chat runs its repository’s run script (set in the repository settings, never in your repository) and previews whatever it serves. Screenplay picks the port for each chat. The one requirement on your app: the dev server must listen on the port it’s given.

Most frameworks do this out of the box, because Screenplay passes the port in the standard PORT environment variable.

Every chat’s dev server runs on your machine, so each one needs its own port. The run script is started under portless, which sets PORT to the port allocated to that chat:

# Next.js, Create React App, Express, Nuxt… honor $PORT already npm run dev # Vite and other tools that ignore $PORT: pass it explicitly vite --port $PORT --strictPort # A custom server node server.js --port $PORT

portless ships with the app, and Screenplay starts its proxy for you. It also gives each chat a stable URL like http://my-branch.my-app.localhost:1355 that survives dev server restarts. Open in browser on a chat opens it.

If you run npx portless proxy start yourself (it asks for sudo to use port 443 and trust a local HTTPS certificate), Screenplay uses that proxy instead, and the stable URLs drop the port: https://my-branch.my-app.localhost. npx portless service install does the same and starts that proxy whenever your Mac starts.

A script that honors $PORT works on both.

When the preview never loads

On desktop, a dev server that never listens on its assigned port fails with a clear error (DevServerPortIgnoredError) instead of leaving a blank frame. The usual cause is a script that ignores $PORT:

  1. Fix the Run script in the repository settings (for example add --port $PORT).
  2. Use Restart → Restart dev server on the chat.
  3. Still stuck? The chat’s Dev server terminal (under its composer) shows the dev server’s and portless’s output. The chat’s agent can read the same output and restart the dev server, so you can also ask it to debug the preview.

Troubleshooting lists the other ways a preview can fail.

Monorepos

A repository on a canvas previews one app. Filter your monorepo’s dev command down to that app, and pass the port as a flag:

# Turborepo turbo run dev --filter=web -- --port $PORT # pnpm workspaces pnpm --filter web dev -- --port $PORT

With Turborepo, pass the port as a flag, as above, instead of relying on the PORT variable reaching the task. Turborepo 2’s strict env mode strips undeclared variables, so $PORT is empty inside the task. Package scripts that hardcode --port 3001 also win over the variable. The appended flag handles both, because for Next.js and Vite the last --port wins. Alternatively, add "passThroughEnv": ["PORT"] to the dev task in turbo.json.

To work on a second app from the same monorepo, add the repository again with its own run script and a name such as web or api; see Monorepos.

Why it works this way

  • On desktop, chats run directly on your machine, not in containers, so your already-authenticated tools (including coding CLIs on a subscription login) work inside every chat.
  • Adopting Screenplay should never require changing your code. The run script lives in Screenplay’s settings, and Screenplay invokes portless itself, so your repository needs no config files or dependencies.
Last updated on