diff --git a/.conductor/README.md b/.conductor/README.md index 5c8df4f6..77ed3b07 100644 --- a/.conductor/README.md +++ b/.conductor/README.md @@ -52,29 +52,39 @@ Hit **dev** and both servers come up; click Conductor's **Open** button to launc the UI. Start **worker** once (e.g. in your primary workspace) when you need background jobs — the same way you used to run a single arq worker in VS Code. -## Proving you're in the right worktree - -`run-ui.sh` exports `NEXT_PUBLIC_WORKSPACE_NAME=$CONDUCTOR_WORKSPACE_NAME`, which -`ui/src/components/WorkspaceBadge.tsx` renders as a small color-coded pill in the -bottom-left corner (e.g. `⬡ pattaya :8200`). The color is derived from the -workspace name, so two worktrees are instantly distinguishable. The badge is -invisible in production and in a plain `npm run dev` (no env var set). - ## Creating a new workspace -In Conductor: **New Workspace** → pick a branch. Conductor first copies the -gitignored env files listed in `../.worktreeinclude` (`api/.env`, `ui/.env`, -`ui/.env.local`, …) from your main checkout, then `setup.sh` runs automatically -and: +In Conductor: **New Workspace** → pick a branch. `setup.sh` then runs +automatically and: -1. checks out the `pipecat` submodule, -2. builds `venv` (Python 3.13) + installs backend/pipecat deps, -3. `npm install` for the UI, -4. ensures the shared Docker stack is up, -5. runs `alembic upgrade head`. +1. copies the gitignored env files from your main checkout (see + [Environment files](#environment-files)), +2. checks out the `pipecat` submodule, +3. builds `venv` (Python 3.13) + installs backend/pipecat deps, +4. `npm install` for the UI, +5. ensures the shared Docker stack is up, +6. runs `alembic upgrade head`. The first setup is slow (deps); afterwards the Run buttons are instant. +## Environment files + +The app's env files hold real secrets, so they're **gitignored** and never +committed — a fresh worktree won't have them. `setup.sh` copies them from your +main checkout (`$CONDUCTOR_ROOT_PATH`) into each new workspace: + +| File | Used by | +| ----------------------------- | -------------------------------- | +| `api/.env` | backend (DB/Redis URLs, secrets) | +| `api/.env.test` | backend test runs | +| `ui/.env` | UI (backend URL, public config) | +| `ui/.env.local` | UI secrets (Stack/PostHog/etc.) | +| `ui/.env.sentry-build-plugin` | UI Sentry source-map upload | + +The copy is idempotent (only fills in what's missing), so re-running setup won't +clobber a workspace-local edit. **Add a new env file?** List it in the loop near +the top of `setup.sh`. + ## Files | File | Purpose | @@ -85,7 +95,6 @@ The first setup is slow (deps); afterwards the Run buttons are instant. | `run-ui.sh` | Foreground Next.js on `$CONDUCTOR_PORT` | | `run-backend.sh` | Foreground uvicorn on `$CONDUCTOR_PORT + 1` | | `run-worker.sh` | Foreground Arq worker (run in one workspace only) | -| `../.worktreeinclude` | Gitignored env files Conductor copies per workspace | > Need machine-local tweaks (e.g. a different port base or skipping the worker)? > Put them in `.conductor/settings.local.toml`, which is personal and not diff --git a/.conductor/run-ui.sh b/.conductor/run-ui.sh index 949325ab..9c0bd79b 100755 --- a/.conductor/run-ui.sh +++ b/.conductor/run-ui.sh @@ -1,10 +1,8 @@ #!/usr/bin/env bash # Conductor run script — UI (Next.js) for THIS workspace. # -# Binds $CONDUCTOR_PORT (so Conductor's Open button / preview_urls land here), -# talks to this workspace's backend on $CONDUCTOR_PORT + 1, and tags the build -# with the workspace identity (NEXT_PUBLIC_WORKSPACE_NAME) so the in-app -# WorkspaceBadge shows which worktree you're looking at. Foreground exec (no &) +# Binds $CONDUCTOR_PORT (so Conductor's Open button / preview_urls land here) and +# talks to this workspace's backend on $CONDUCTOR_PORT + 1. Foreground exec (no &) # so Conductor can stop it cleanly. set -euo pipefail cd "${CONDUCTOR_WORKSPACE_PATH:-$PWD}" @@ -22,11 +20,10 @@ if ! command -v node >/dev/null 2>&1; then fi # Shell env overrides .env files in Next.js, so this points the UI at the right -# backend and stamps the workspace name into the client bundle. +# backend for this workspace. export BACKEND_URL="$BACKEND" export NEXT_PUBLIC_BACKEND_URL="$BACKEND" -export NEXT_PUBLIC_WORKSPACE_NAME="${CONDUCTOR_WORKSPACE_NAME:-local}" cd ui -echo "[ui] workspace=${NEXT_PUBLIC_WORKSPACE_NAME} port=${UI_PORT} backend=${BACKEND}" +echo "[ui] workspace=${CONDUCTOR_WORKSPACE_NAME:-?} port=${UI_PORT} backend=${BACKEND}" exec npm run dev -- --port "$UI_PORT" diff --git a/.conductor/setup.sh b/.conductor/setup.sh index e340c47d..6aa4f844 100755 --- a/.conductor/setup.sh +++ b/.conductor/setup.sh @@ -2,9 +2,8 @@ # Conductor setup script — runs ONCE when a workspace (git worktree) is created. # # A fresh worktree only has git-tracked files, so this recreates the rest: the -# pipecat submodule checkout, a Python venv, ui/node_modules, the shared local -# Docker stack, and the DB schema. (Gitignored env files are copied separately -# by .worktreeinclude, BEFORE this script runs.) +# gitignored env files, the pipecat submodule checkout, a Python venv, +# ui/node_modules, the shared local Docker stack, and the DB schema. # # Conductor injects: CONDUCTOR_ROOT_PATH (main checkout), CONDUCTOR_WORKSPACE_PATH, # CONDUCTOR_WORKSPACE_NAME, CONDUCTOR_PORT (first of 10), CONDUCTOR_IS_LOCAL. @@ -16,16 +15,17 @@ cd "$WS" log() { printf '\n\033[1;36m[conductor-setup]\033[0m %s\n' "$*"; } -# 1) Env files — normally copied by .worktreeinclude BEFORE this runs (the -# Conductor-native file-copy mechanism). This block is only a FALLBACK so that -# `bash .conductor/setup.sh` also works when run by hand outside Conductor: it -# copies just the files that are still missing, and is a no-op under Conductor. +# 1) Copy the gitignored env files from the main checkout. These hold real +# secrets, so they're never committed — a fresh worktree won't have them. We copy +# only what's missing (idempotent), so re-running setup won't clobber local edits. +# (See README "Environment files" for the canonical list.) if [[ -n "$ROOT" && "$ROOT" != "$WS" ]]; then + log "Copying gitignored env files from $ROOT" for f in api/.env api/.env.test ui/.env ui/.env.local ui/.env.sentry-build-plugin; do if [[ ! -f "$f" && -f "$ROOT/$f" ]]; then mkdir -p "$(dirname "$f")" cp "$ROOT/$f" "$f" - log "fallback-copied $f (not present from .worktreeinclude)" + echo " copied $f" fi done fi diff --git a/.worktreeinclude b/.worktreeinclude deleted file mode 100644 index 898da064..00000000 --- a/.worktreeinclude +++ /dev/null @@ -1,10 +0,0 @@ -# Conductor: gitignored files copied from the main checkout into every new -# workspace (git worktree), BEFORE .conductor/setup.sh runs. These hold real -# secrets and are .gitignored, so a fresh worktree wouldn't otherwise have them. -# Patterns are gitignore-style. Adding this file overrides Conductor's default -# ".env*" copy, so list everything local dev needs explicitly. -api/.env -api/.env.test -ui/.env -ui/.env.local -ui/.env.sentry-build-plugin diff --git a/ui/src/app/layout.tsx b/ui/src/app/layout.tsx index 2b621682..15b4cfb5 100644 --- a/ui/src/app/layout.tsx +++ b/ui/src/app/layout.tsx @@ -10,7 +10,6 @@ import PostHogIdentify from "@/components/PostHogIdentify"; import { SentryErrorBoundary } from "@/components/SentryErrorBoundary"; import SpinLoader from "@/components/SpinLoader"; import { ThemeProvider } from "@/components/ThemeProvider"; -import WorkspaceBadge from "@/components/WorkspaceBadge"; import { Toaster } from "@/components/ui/sonner"; import { AppConfigProvider } from "@/context/AppConfigContext"; import { OnboardingProvider } from "@/context/OnboardingContext"; @@ -88,7 +87,6 @@ export default function RootLayout({ - ); diff --git a/ui/src/components/WorkspaceBadge.tsx b/ui/src/components/WorkspaceBadge.tsx deleted file mode 100644 index bf7f61be..00000000 --- a/ui/src/components/WorkspaceBadge.tsx +++ /dev/null @@ -1,43 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; - -/** - * Dev-only badge that proves which Conductor workspace this UI belongs to. - * - * Renders nothing unless NEXT_PUBLIC_WORKSPACE_NAME is set — which only happens - * when the UI is launched via .conductor/run-ui.sh. So production builds and a - * plain `npm run dev` are completely unaffected. - * - * The pill color is derived deterministically from the workspace name, so two - * worktrees running side by side are instantly distinguishable at a glance. - */ -export default function WorkspaceBadge() { - const workspace = process.env.NEXT_PUBLIC_WORKSPACE_NAME; - const backend = process.env.NEXT_PUBLIC_BACKEND_URL; - const [port, setPort] = useState(""); - - useEffect(() => { - setPort(window.location.port); - }, []); - - if (!workspace) return null; - - // Deterministic hue from the workspace name. - let hash = 0; - for (let i = 0; i < workspace.length; i++) { - hash = (hash * 31 + workspace.charCodeAt(i)) >>> 0; - } - const hue = hash % 360; - - return ( -
- ⬡ {workspace} - {port ? ` :${port}` : ""} -
- ); -}