chore: remove WorkspaceBadge test UI and .worktreeinclude (setup.sh + README handle env copy)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Abhishek Kumar 2026-06-29 13:21:21 +05:30
parent de88d4f21e
commit f190a0dd9a
6 changed files with 39 additions and 88 deletions

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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({
</AuthProvider>
</SentryErrorBoundary>
</ThemeProvider>
<WorkspaceBadge />
</body>
</html>
);

View file

@ -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 (
<div
className="pointer-events-none fixed bottom-2 left-2 z-[9999] select-none rounded-full px-2.5 py-1 font-mono text-[11px] font-medium text-white shadow-md"
style={{ backgroundColor: `hsl(${hue} 70% 38% / 0.92)` }}
title={`Conductor workspace: ${workspace}\nUI port: ${port}\nBackend: ${backend ?? "?"}`}
>
{workspace}
{port ? ` :${port}` : ""}
</div>
);
}