Decouple workspace port from Conductor via WORKSPACE_PORT#1575
Conversation
The per-workspace port (used for the database name, session cookie, and dev host) was read directly from Conductor's CONDUCTOR_PORT, hardcoding a dependency on one specific tool. This makes the isolation mechanism work for anyone running parallel worktrees, not just Conductor users. The app now reads the generic WORKSPACE_PORT everywhere. The Conductor entry scripts (bin/conductor-*) are the only place CONDUCTOR_PORT is referenced — they translate it into WORKSPACE_PORT, which is also the only env Conductor actually injects into those processes. Non-Conductor setups just export WORKSPACE_PORT themselves. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| # bin/setup) only references WORKSPACE_PORT. Export it before bin/setup runs | ||
| # so the per-workspace database is created with the right suffix. | ||
| export WORKSPACE_PORT=${WORKSPACE_PORT:-${CONDUCTOR_PORT:-}} | ||
|
|
There was a problem hiding this comment.
🤖 From Claude: This export must stay above the bin/setup call so the per-workspace database is created with the right WORKSPACE_PORT suffix. These three conductor-* scripts are the only place CONDUCTOR_PORT is referenced now.
| # | ||
| # WORKSPACE_PORT gives each parallel workspace its own database. Under Conductor | ||
| # it is derived from CONDUCTOR_PORT by the bin/conductor-* scripts. | ||
| <% workspace_port = ENV["WORKSPACE_PORT"] %> |
There was a problem hiding this comment.
🤖 From Claude: The app intentionally reads only WORKSPACE_PORT — no CONDUCTOR_PORT fallback here. Translation happens once, upstream, in the bin/conductor-* scripts (the only processes Conductor injects CONDUCTOR_PORT into).
There was a problem hiding this comment.
Pull request overview
Decouples the app’s “per-workspace isolation” (DB name suffix, session cookie key, and dev hostname behavior) from Conductor-specific CONDUCTOR_PORT by standardizing on a generic WORKSPACE_PORT, with Conductor scripts translating CONDUCTOR_PORT → WORKSPACE_PORT.
Changes:
- Switch Rails config points (DB, session store, default host) from
CONDUCTOR_PORTtoWORKSPACE_PORT. - Update Conductor lifecycle scripts to export
WORKSPACE_PORTand drivePORTfrom it. - Document the new contract in
CONTRIBUTING.mdand updateai/serverto useWORKSPACE_PORT.
Reviewed changes
Copilot reviewed 5 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| CONTRIBUTING.md | Documents WORKSPACE_PORT as the app-level contract and Conductor as an optional provider. |
| config/initializers/session_store.rb | Uses WORKSPACE_PORT to suffix the session cookie key for workspace isolation. |
| config/initializers/default_host.rb | Uses WORKSPACE_PORT to choose awbw.local vs localhost in development. |
| config/database.yml | Uses WORKSPACE_PORT to suffix development/test DB names. |
| bin/conductor-setup | Exports WORKSPACE_PORT upstream of bin/setup; uses it to compute PORT. |
| bin/conductor-server | Exports WORKSPACE_PORT and derives PORT/VITE_RUBY_PORT for Conductor workspaces. |
| bin/conductor-archive | Uses WORKSPACE_PORT for port cleanup and deciding whether to drop workspace DBs. |
| ai/server | Uses WORKSPACE_PORT (if set) as the chosen dev server port. |
The conductor-* scripts export WORKSPACE_PORT even when neither it nor CONDUCTOR_PORT is set, so Rails receives an empty string rather than nil. Since "" is truthy in Ruby, that would suffix the database name and session cookie with a bare underscore and switch the dev host to awbw.local. Use `.presence` so only a non-empty value takes effect. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What is the goal of this PR and why is this important?
CONDUCTOR_PORT, hardcoding a dependency on one specific tool.How did you approach the change?
WORKSPACE_PORTenv var everywhere (config/database.yml,config/initializers/session_store.rb,config/initializers/default_host.rb,ai/server).bin/conductor-setup,bin/conductor-server,bin/conductor-archive) are now the only placeCONDUCTOR_PORTis referenced — each exportsWORKSPACE_PORT=${WORKSPACE_PORT:-${CONDUCTOR_PORT:-}}near the top, so everything they spawn inherits it.CONDUCTOR_PORTis only injected into those three script processes, not the interactive terminal — so translating it once, upstream, is the natural seam.bin/conductor-setupthe export happens beforebin/setupruns so the per-workspace database is created with the right suffix.CONTRIBUTING.md: Conductor is one optional platform; any other setup can get the same isolation by exportingWORKSPACE_PORT.Verification
Confirmed via
bin/rails runnerthat the resolved database/cookie are correct in each case:WORKSPACE_PORT=4567(any system)awbw_development_4567/_awbw_session_4567CONDUCTOR_PORT→ script exportsWORKSPACE_PORTCONDUCTOR_PORTwith no translationawbw_developmentShell scripts pass
sh -n; Rubocop clean on changed Ruby files.Anything else to add?
CONDUCTOR_PORTfallback in the app anymore, so a non-Conductor user must exportWORKSPACE_PORTthemselves to get an isolated DB/port. This is the intended decoupling and matches prior behavior in the interactive terminal (whereCONDUCTOR_PORTwas never present).🤖 Generated with Claude Code