Skip to main content
A run script is a shell command saved on a repo. When you press Play in the run sidebar, p0 spawns the script in a PTY rooted at the repo’s checkout.

Configuring a script

Each repo row in the repo manager has a run-script editor (it’s also reachable from the run sidebar’s “No run script configured” empty state). The dialog is titled Run Script and contains:
  • A textarea for the command. Placeholder is e.g. bun run dev. Any shell command goes here — single line or multi-line.
  • A button labeled Add path-specific run command for monorepos. Each entry is a sub-path inside the repo (e.g. apps/api) with its own script. The path input autocompletes from the repo’s directory listing.
Saving the dialog with an empty textarea clears the root script. Toast: Run script cleared for .

How p0 invokes it

When you press Play, p0:
  1. Looks up the saved script for that repo (or sub-path).
  2. Writes it to a temp file — .sh with a #!/bin/bash shebang on macOS/Linux, .cmd on Windows.
  3. Spawns a PTY with the working directory set to {worktree}/repos/{repo-name} (plus the sub-path, if any) and runs the temp file (exec bash <path> on Unix, call "<path>" & exit /B on Windows).
  4. Streams stdout/stderr into the xterm.js pane in the run sidebar.
The PTY accepts stdin, so prompts like “Ok to proceed? (y)” work — type into the pane and the keystrokes go to the process.

Multiple scripts per repo

There’s one root script per repo. On top of that, you can add any number of path-specific scripts for sub-directories — useful for monorepos where apps/web and apps/api each need their own dev command. Every sub-path with a script becomes its own tab in the run sidebar, labelled {repo}/{sub-path}.

Lifecycle: Start, Stop, restart

The controls bar on each run-sidebar tab has a single Play/Stop button plus a status dot:
  • Gray dot — idle, not started this session.
  • Green dot — running.
  • Red dot — exited. The exit code shows on the right when it’s non-zero.
Start is idempotent — pressing Play while the process is already running is a no-op and returns the same pane. Stop is lenient — it returns success even if the process has already exited. Pressing Play after an exit resets the terminal and spawns a fresh process.