diff --git a/HANDOVER.md b/HANDOVER.md deleted file mode 100644 index 59fd524..0000000 --- a/HANDOVER.md +++ /dev/null @@ -1,84 +0,0 @@ -# Handover — Context Studio Wizard - -_Last updated: 2026-03-09_ - -## Current status - -The wizard runs end-to-end. The generated project (`thewiztest`) starts the container -and opens the Electron UI. **The last fix was NOT yet confirmed working by the user.** -The session ended before the user could test it. - -## What was fixed this session (newest first) - -### 1. `bin/claude` — workdir fallback (UNVERIFIED — last fix, not yet tested) -**File:** `lib/container.sh` → generated `bin/claude` -**Symptom:** `[Server:err] claude-code is required but not found` → `[Server] Exited with code 1` → all agents fail to start -**Root cause:** When Electron spawns `node core/start.js`, its cwd is `~/.context-studio/core`. The `bin/claude` wrapper used `--workdir "$PWD"` in `podman exec`. That directory isn't mounted in the container → podman fails → returns non-zero → claude appears "missing". -**Fix:** If `$PWD` is not under `$PROJECT_DIR`, fall back to `$PROJECT_DIR` as the container workdir. -**Also patched:** `thewiztest/bin/claude` - -### 2. Container runs as root → `--dangerously-skip-permissions` rejected -**File:** `lib/container.sh` → generated `start.sh` -**Symptom:** `--dangerously-skip-permissions cannot be used with root/sudo privileges` -**Fix:** Added `--user "$(id -u):$(id -g)"` and `-e HOME="$HOME"` to `podman run` -**Why it works:** Host user `elmar` = uid 1000 = `node` user in `node:22` image → permissions match -**Also patched:** `thewiztest/start.sh` - -### 3. Electron manages server startup — removed redundant headless node -**File:** `lib/container.sh` → generated `start.sh` -**Symptom:** Would have caused port conflicts -**Fix:** Removed `node start.js --ui-mode=headless &` from start.sh. The Electron app's `server-management.js` checks the lock file and spawns servers itself. -**Also patched:** `thewiztest/start.sh` - -### 4. Electron must be launched separately -**File:** `lib/container.sh` -**Symptom:** UI never opened — servers ran but no window -**Root cause:** `node core/start.js --ui-mode=electron` does NOT launch Electron. It logs "Electron app started separately" and only manages A2A servers. -**Fix (later superseded):** Direct Electron launch via `$CS_CORE/app/node_modules/.bin/electron $CS_CORE/app` - -## What still needs verifying - -1. **Does the server now start without the `claude-code missing` error?** - - Run `./start.sh` in `thewiztest/` - - Watch for `[12:xx:xx] ✅ All agent servers started` (no `Server startup failed`) - - The Electron UI should open and kai's terminal should start without root errors - -2. **`localhost:null` network error** — this is downstream of (1). If servers start cleanly, the registry port gets written to the lock file and `localhost:null` disappears. - -3. **Kai can't connect to the internet** — mentioned by user but not investigated. Could be: - - Container network settings (Podman default: slirp4netns, should have internet) - - ANTHROPIC_API_KEY not set or not passed into container - - Proxy/VPN issue on the host network - -## Key architecture facts - -### How CS Core + Electron work together -- `electron app/` starts the UI -- Electron's `server-management.js` checks `workflow/data/` for a lock file -- If no lock file → it spawns `node core/start.js --ui-mode=headless` as a child process -- Child process inherits Electron's `process.env` including PATH (with `bin/claude`) -- When the requirements check runs `claude --version`, it finds `bin/claude` in PATH -- `bin/claude` proxies to `podman exec cs- claude --version` -- Container must be running BEFORE Electron is launched (start.sh handles this) - -### Path that must be mounted in container -Only `$PROJECT_DIR` is mounted (at the same absolute path). NOT: -- `~/.context-studio/core` -- `~/.anthropic` (mounted read-only separately) -- Any other host path - -### Generated files per project -- `bin/claude` — wrapper with hardcoded `PROJECT_DIR` and `CONTAINER_NAME` -- `start.sh` — starts container as `$(id -u):$(id -g)`, exports PATH, launches Electron -- `stop.sh` — force-removes container -- `update.sh` — git pull core, npm update claude-code in container, apt upgrade - -## File locations -- Wizard: `/home/elmar/Projects/ContextStudioWizard/` -- Test project: `/home/elmar/Projects/thewiztest/` -- Core (read-only!): `/home/elmar/.context-studio/core/` -- Wizard repo remote: check `git remote -v` in ContextStudioWizard - -## What NOT to do -- Never modify `~/.context-studio/core` — it is read-only -- Never commit or push to the core repo diff --git a/README.md b/README.md index ba9267f..c89f5ff 100644 --- a/README.md +++ b/README.md @@ -6,40 +6,18 @@ ## ✨ What it does -One command. A complete project drops out: +One command. One conversation. A complete project drops out: ``` ~/.context-studio/core/ ← 🔧 installed once, shared globally -~/Projects/my-project/ -├── .devcontainer/ ← 🐳 Node 22 · Rust · Claude Code +~/projects/my-project/ +├── .devcontainer/ ← 🐳 Node 22 · Rust · Claude Code · Electron deps ├── workflow/ ← 🤖 agents, roles, A2A config, project docs -├── src/ ← 💻 your code -├── bin/claude ← 🔀 wrapper: routes claude → container -├── start.sh ← ▶️ start container + Context Studio UI -├── stop.sh ← ⏹️ stop the agents container -└── update.sh ← 🔄 update core, claude-code, OS packages +└── src/ ← 💻 your code ``` -Run `./start.sh` → Podman container starts → Electron UI opens → talk to your agent team. - ---- - -## 🏗️ Architecture (Option B) - -``` -HOST CONTAINER (cs-) -───────────────────────────── ──────────────────────── -Context Studio Core (Electron) ←─── All Claude Code agents - starts A2A servers mounted at same abs path - opens Electron UI bin/claude wrapper routes - manages workflow every claude call here -``` - -- **CS Core** runs on the host (Electron UI, no display issues) -- **All agents** run inside the Podman container as the current user (not root) -- **`bin/claude`** is prepended to PATH so CS Core's server process finds it automatically -- **Paths match** host ↔ container (project mounted at the same absolute path) +Open in devcontainer → start Context Studio → talk to your agent team. --- @@ -54,6 +32,8 @@ Context Studio Core (Electron) ←─── All Claude Code agents **Auto-install supported on:** Arch · Debian/Ubuntu · RHEL/Fedora · openSUSE +> The wizard detects your distro and installs `git` and `podman`/`docker` automatically if they are missing. SSH key and API key must be set up by you. + --- ## 🚀 Usage @@ -64,50 +44,57 @@ Context Studio Core (Electron) ←─── All Claude Code agents The wizard guides you through: -1. 🔧 **Core setup** — clones `context-studio-core` to `~/.context-studio/core/` (once, shared) +1. 🔧 **Core setup** — clones `context-studio-core` to `~/.context-studio/core/` (once) 2. 📝 **Project name & location** 3. ⚙️ **Workflow** — generate from scratch _or_ clone an existing repo 4. 🤖 **Agent preset** _(if generating)_ | Preset | Agents | |--------|--------| - | `minimal` | 5 agents: coordinator · 2× coder · researcher · tester | - | `standard` | 9 agents: 2× coordinator · 3× coder · 2× researcher · tester · reviewer | + | `minimal` | 🎯 coordinator · 2× coder · researcher · tester | + | `standard` | 🎯🎯 2× coordinator · 3× coder · 2× researcher · tester · reviewer | -5. ✅ **Done** — project created, git repo initialized - -> ⚠️ **First `./start.sh`** builds the container image. Expect 5–15 min. Subsequent starts are instant. +5. ✅ **Done** — git repo initialized, devcontainer ready --- -## ▶️ Starting your project +## 📂 Open the project +**🖥️ VS Code** ```bash -cd ~/Projects/my-project -./start.sh +code ~/projects/my-project # → "Reopen in Container" ``` -This will: -1. Build the container image if not yet built (first run: 5–15 min) -2. Start the Podman container (agents run here as your user, not root) -3. Launch the Context Studio Electron UI -4. When you close the UI → container is stopped automatically - +**⌨️ CLI** ```bash -./stop.sh # force-stop container without closing the UI -./update.sh # update core, claude-code inside container, OS packages +cd ~/projects/my-project +docker build -t my-project .devcontainer/ +docker run -it --rm \ + -v "$(pwd)":/workspace \ + -v "$HOME/.context-studio/core":/opt/context-studio/core \ + -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \ + my-project bash +``` + +**▶️ Start Context Studio** _(inside container)_ +```bash +node $CS_CORE_DIR/core/start.js # Electron UI +node $CS_CORE_DIR/core/start.js --ui-mode=headless # servers only ``` --- -## 🔄 How `bin/claude` works +## 🌍 Mobility -CS Core on the host needs to call `claude`. Instead of using the host's `claude`, `start.sh` prepends `bin/claude` to `PATH`. This wrapper: +Commit your project. On any machine: -1. Checks the agents container is running -2. Relays the call into the container via `podman exec` -3. Passes the working directory (falling back to project root if cwd isn't mounted) -4. All agents — including the main coordinator — run **inside the container** +```bash +git clone +cd my-project +code . # done +``` + +> Core is re-cloned automatically on first run. Only `ANTHROPIC_API_KEY` is needed on the host. --- @@ -116,12 +103,10 @@ CS Core on the host needs to call `claude`. Instead of using the host's `claude` ``` 🧙 wizard.sh ← entry point 📁 lib/ - utils.sh ← prompts, colors, gum helpers - prereqs.sh ← auto-install git + podman/docker + utils.sh ← prompts, colors, helpers core.sh ← global core install/update project.sh ← devcontainer + project scaffold workflow.sh ← generate or clone workflow config - container.sh ← generates start/stop/update/bin/claude 📁 templates/ Dockerfile ← Node 22 + Rust + build tools + Claude Code devcontainer.json ← mounts, env vars, VS Code extensions @@ -131,22 +116,3 @@ CS Core on the host needs to call `claude`. Instead of using the host's `claude` 📁 roles/ ← coordinator, coder, researcher, tester, reviewer 📁 hooks/rules/ ← per-role tool restrictions ``` - ---- - -## ⚠️ Hard rules - -- **`~/.context-studio/core` is READ-ONLY** — never modify, commit, or push to it -- It is a shared global dependency; the wizard only clones and `npm install`s it - ---- - -## 🌍 Portability - -Commit your project. On any machine: - -```bash -git clone -cd my-project -./start.sh # wizard re-runs if core missing; image builds on first run -``` diff --git a/lib/container.sh b/lib/container.sh index 224b1c5..11072fb 100644 --- a/lib/container.sh +++ b/lib/container.sh @@ -17,7 +17,6 @@ generate_container_scripts() { # Claude Code wrapper — runs claude inside the agents container. # CS Core on the host calls this instead of the real claude binary. CONTAINER_NAME="${container_name}" -PROJECT_DIR="${project_dir}" RUNTIME="\$(command -v podman || command -v docker || true)" if [[ -z "\$RUNTIME" ]]; then @@ -31,21 +30,11 @@ if ! "\$RUNTIME" container inspect "\$CONTAINER_NAME" --format '{{.State.Running exit 1 fi -# Use PWD as workdir only if it is inside the mounted project tree. -# When CS Core's server process calls claude --version its cwd is the -# core directory (~/.context-studio/core) which is NOT mounted, causing -# podman exec --workdir to fail. Fall back to PROJECT_DIR in that case. -if [[ "\$PWD" == "\$PROJECT_DIR"* ]]; then - WORKDIR="\$PWD" -else - WORKDIR="\$PROJECT_DIR" -fi - # Pass through TTY if available, relay working directory into container if [ -t 0 ]; then - exec "\$RUNTIME" exec -it --workdir "\$WORKDIR" "\$CONTAINER_NAME" claude "\$@" + exec "\$RUNTIME" exec -it --workdir "\$PWD" "\$CONTAINER_NAME" claude "\$@" else - exec "\$RUNTIME" exec -i --workdir "\$WORKDIR" "\$CONTAINER_NAME" claude "\$@" + exec "\$RUNTIME" exec -i --workdir "\$PWD" "\$CONTAINER_NAME" claude "\$@" fi WRAPPER chmod +x "$project_dir/bin/claude" @@ -85,18 +74,14 @@ mkdir -p "\$HOME/.anthropic" # ── Start agents container ─────────────────────────────────────────────── # Mount project at the same absolute path so host and container paths match. # CS Core sets agent working dirs to host paths; the wrapper relays PWD. -# Run as uid/gid of the current user so Claude Code doesn't run as root -# (--dangerously-skip-permissions is blocked when running as root). echo "→ Starting agents container '\$CONTAINER_NAME'..." "\$RUNTIME" run -d \\ --name "\$CONTAINER_NAME" \\ - --user "\$(id -u):\$(id -g)" \\ -v "\$PROJECT_DIR:\$PROJECT_DIR" \\ -v "\$HOME/.anthropic:\$HOME/.anthropic:ro" \\ -e ANTHROPIC_API_KEY="\${ANTHROPIC_API_KEY:-}" \\ -e CS_WORKFLOW_DIR="\$PROJECT_DIR/workflow" \\ -e PROJECT_ROOT_DIR="\$PROJECT_DIR" \\ - -e HOME="\$HOME" \\ "\$IMAGE_NAME" \\ sleep infinity @@ -128,21 +113,17 @@ if [[ -z "\${DISPLAY:-}" && -z "\${WAYLAND_DISPLAY:-}" ]]; then fi # ── Put claude wrapper first on PATH ──────────────────────────────────── -# Electron inherits this PATH and passes it to the A2A server it spawns, -# so the servers can locate the bin/claude wrapper inside the container. export PATH="\$PROJECT_DIR/bin:\$PATH" -# ── Launch Context Studio (Electron manages A2A server startup) ────────── -# The Electron app checks for a lock file; if servers aren't running it -# spawns core/start.js --ui-mode=headless internally and waits for health. -echo "→ Launching Context Studio..." +# ── Launch CS Core on the host ─────────────────────────────────────────── +echo "→ Starting Context Studio Core..." CS_CORE_DIR="\$CS_CORE" \\ CS_WORKFLOW_DIR="\$PROJECT_DIR/workflow" \\ PROJECT_ROOT_DIR="\$PROJECT_DIR" \\ -"\$CS_CORE/app/node_modules/.bin/electron" "\$CS_CORE/app" +node "\$CS_CORE/core/start.js" -# ── Electron closed — stop container ───────────────────────────────────── -echo "→ UI closed. Stopping agents container..." +# ── CS Core exited — stop container ───────────────────────────────────── +echo "→ Stopping agents container..." "\$RUNTIME" rm -f "\$CONTAINER_NAME" 2>/dev/null || true START chmod +x "$project_dir/start.sh"