Problem
When clicking Play, the user has zero visibility into which run script will execute. There are multiple potential sources (Project Settings DB, pane.json, conductor.json, .gitpod.yml, devcontainer.json) resolved via a hidden priority hierarchy. The user can't see what's resolved and can't pick an alternative.
Proposed Solution: Split-Button Play UX
Phase 1: Frontend split-button (small scope)
-
Resolve all available run sources upfront when the project loads — new IPC call projects:get-run-sources returns all candidates:
[
{ "source": "project-settings", "command": null },
{ "source": "pane.json", "command": "pnpm dev" },
{ "source": "conductor.json", "command": null }
]
-
Play button gets a split button — main button runs the current selection, chevron opens a popover listing available sources with their commands. User picks one, it becomes the active choice (persisted per-project).
-
Show what will run — tooltip on the Play button: pnpm dev (from pane.json).
Backend stays unchanged — resolution logic remains in projects:run-script, just add one new IPC call, and the complexity is entirely in the frontend split-button component.
Phase 2: Run service consolidation (future, larger scope)
Currently run script execution is spread across multiple services:
runCommandManager.ts — manages project_run_commands table entries, PTY execution
logsManager.runScript() — spawns child processes with shell/WSL support, streams to logs panel
scriptExecutionTracker.ts — tracks which script is running globally
projects:run-script IPC handler — orchestrates stop-existing → resolve → execute flow
These could be consolidated into a unified RunService that owns the full lifecycle: source resolution, execution, process management, and state tracking. This would simplify the Play button handler and make it easier to add features like concurrent run scripts or per-session run overrides.
Context
This came up during the pane.json config detection implementation, which added auto-detection of run scripts from pane.json, conductor.json, .gitpod.yml, and devcontainer.json as fallbacks when no DB run_script is configured. The detection works but the UX doesn't surface which source won.
Problem
When clicking Play, the user has zero visibility into which run script will execute. There are multiple potential sources (Project Settings DB, pane.json, conductor.json, .gitpod.yml, devcontainer.json) resolved via a hidden priority hierarchy. The user can't see what's resolved and can't pick an alternative.
Proposed Solution: Split-Button Play UX
Phase 1: Frontend split-button (small scope)
Resolve all available run sources upfront when the project loads — new IPC call
projects:get-run-sourcesreturns all candidates:[ { "source": "project-settings", "command": null }, { "source": "pane.json", "command": "pnpm dev" }, { "source": "conductor.json", "command": null } ]Play button gets a split button — main button runs the current selection, chevron opens a popover listing available sources with their commands. User picks one, it becomes the active choice (persisted per-project).
Show what will run — tooltip on the Play button:
pnpm dev (from pane.json).Backend stays unchanged — resolution logic remains in
projects:run-script, just add one new IPC call, and the complexity is entirely in the frontend split-button component.Phase 2: Run service consolidation (future, larger scope)
Currently run script execution is spread across multiple services:
runCommandManager.ts— managesproject_run_commandstable entries, PTY executionlogsManager.runScript()— spawns child processes with shell/WSL support, streams to logs panelscriptExecutionTracker.ts— tracks which script is running globallyprojects:run-scriptIPC handler — orchestrates stop-existing → resolve → execute flowThese could be consolidated into a unified
RunServicethat owns the full lifecycle: source resolution, execution, process management, and state tracking. This would simplify the Play button handler and make it easier to add features like concurrent run scripts or per-session run overrides.Context
This came up during the
pane.jsonconfig detection implementation, which added auto-detection of run scripts frompane.json,conductor.json,.gitpod.yml, anddevcontainer.jsonas fallbacks when no DB run_script is configured. The detection works but the UX doesn't surface which source won.