feat(workbench): in-codespace onboarding — banner, welcome doc, two-tabs explainer#155
Merged
Merged
Conversation
…abs explainer Three small additions that close the "I clicked the docs button but where's the workbench?" gap a developer hits the first time they launch a codespace. ## The gap GitHub Codespaces auto-opens VS Code Web on workspace boot. Per the devcontainer's `5173.onAutoForward: openBrowserOnce`, GitHub also *tries* to open a second browser tab with the workbench UI as soon as Vite binds. But that popup is often silently swallowed by browser popup-blockers (Safari with strict settings being the worst offender), leaving the developer staring at a VS Code editor with no obvious indication that the playground lives in a *different* tab on `*-5173.app.github.dev`. ## Three fixes in one PR 1. **`.vscode/tasks.json`** — a single task with `runOn: "folderOpen"` that fires automatically the moment VS Code opens this workspace. It runs `.devcontainer/workbench-banner.sh` in a dedicated terminal panel that VS Code reveals to the user. 2. **`.devcontainer/workbench-banner.sh`** — the script the task runs. It waits for Vite to bind (`curl -sf` poll, up to 3 min), then prints a clear `🚀 locus workbench is ready` banner with a ⌘-clickable URL. The URL is constructed from `$CODESPACE_NAME` (set by GitHub) or falls back to `localhost:5173` for local devcontainer runs. Then it tails the three tier logs so the panel stays alive showing liveness. 3. **`.devcontainer/welcome.md`** — opened automatically by the banner script via `code .devcontainer/welcome.md`. A concise getting-started doc with the workbench URL, the two-click provider+run flow, what's running on each port, how to restart tiers if they die, and pointers to the public docs. Plus a clarifying paragraph in `docs/workbench.md` — the "Codespaces — what happens after you click" section now explicitly warns developers that **two browser tabs** will open (VS Code Web first, then the workbench at `*-5173.app.github.dev` once Vite binds), and that if their popup blocker eats the second tab, the in-VS-Code banner is the recovery path. ## Net effect Developer presses Launch workbench. VS Code Web tab opens. Within a few seconds the workbench-banner task fires and pops a dedicated terminal panel saying "🚀 workbench is at <URL>". The welcome.md opens as an editor tab beside it. The forwarded workbench tab also auto-pops in the background unless blocked. Even with the worst popup blocker, the developer has two visible paths to the playground inside their VS Code window — no guessing. Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
fede-kamel
added a commit
that referenced
this pull request
May 12, 2026
… tab (#157) PR #155 added a workspace-open task in `.vscode/tasks.json` that fires the workbench-banner script. That works in principle, but two real-world failure modes turned up in testing: 1. **VS Code Web shows a security prompt** the first time it sees a `runOn: "folderOpen"` task — "Allow folder tasks to run automatically?". If the user dismisses or misses it, the banner never fires. Verified in a fresh codespace: tasks.json was on disk, all three tiers were running, but `ps` showed no `workbench-banner.sh` process. 2. **Org policies that restrict VS Code task auto-run** prevent the task from firing at all in some Codespaces accounts. Devcontainer lifecycle hooks bypass that restriction (different code path inside GitHub). ## Fix Replace the `.vscode/tasks.json` task with a `postAttachCommand` lifecycle hook in `devcontainer.json`. Lifecycle hooks fire every time a client attaches to the running codespace, with no permission prompt and no org-policy guard. Plus: have the banner script call `code --open-external <url>` once Vite is up. That asks VS Code to open the workbench URL in a new browser tab. Because it runs as a user-initiated action inside the VS Code Web session, most popup blockers permit it — unlike the non-initiated `5173.onAutoForward: openBrowserOnce` popup, which Safari and stricter Chrome profiles silently swallow. Two independent paths to "the workbench tab is open": - `onAutoForward: openBrowserOnce` — fires on port-bind, popup-blocker-prone - `code --open-external` — fires from the banner, user-initiated, blocker-resistant If both succeed, the user sees two tabs (harmless). If neither succeeds, the banner still prints the URL and the user clicks it. Three independent paths to the same destination. ## Changes - `.devcontainer/devcontainer.json` — add `postAttachCommand`. - `.devcontainer/workbench-banner.sh` — call `code --open-external` after Vite binds. - `.vscode/tasks.json` — deleted; lifecycle hook supersedes it. Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
4 tasks
fede-kamel
added a commit
that referenced
this pull request
May 12, 2026
…ab Simple Browser) (#158) After researching how high-quality public repos (streamlit/streamlit-example, microsoft/vscode-remote-try-*, n8n, vercel/next.js community templates) handle Codespaces buttons that should land users on a running web app, the dominant pattern is well-established and documented in GitHub's "Customizable Initial Experience" changelog. Our existing #155/#157 setup did the right thing but reached for non-idiomatic primitives. This PR aligns with the convergent best-practice recipe. ## What changes vs main 1. `portsAttributes."5173".onAutoForward`: `openBrowserOnce` → `openPreview`. The forwarded port now opens in VS Code's Simple Browser editor pane (single-tab UX, no separate browser tab, no popup blocker) instead of as a separate external tab. Identical to streamlit-example's port config. 2. `customizations.codespaces.openFiles: [".devcontainer/welcome.md"]` added. Codespaces natively opens these files as editor tabs on first launch — replaces the hand-rolled `code .devcontainer/welcome.md` call that the banner script was doing. 3. `postAttachCommand`: string form → named object form `{"workbench": "bash .devcontainer/workbench-banner.sh"}`. The terminal panel that hosts the command now gets the human label "workbench" instead of an opaque shell tab — matches streamlit's `{"server": "..."}` shape. 4. `postCreateCommand` → `updateContentCommand`. `postCreateCommand` fires once per codespace lifetime (on initial build). `updateContentCommand` fires whenever Codespaces detects content updates (e.g., the user pulls latest main), so deps refresh automatically after a git pull. Streamlit's recommended pattern. 5. `image`: `mcr.microsoft.com/devcontainers/python:3.12-bookworm` → `:1-3.12-bookworm`. Pins the major version of the devcontainer image so future devcontainer-image releases can't unexpectedly break the workbench. Standard practice across the microsoft/vscode-remote-try-* references. ## What's simplified - `workbench-banner.sh` no longer calls `code .devcontainer/welcome.md` (handled by `openFiles`) or `code --open-external <url>` (handled by `openPreview`). The script is now narrowly focused: print the URL banner, tail the three tier logs. - `postStart.sh` no longer calls `code --open-url "vscode://vscode.simpleBrowser.api.open/http://127.0.0.1:5173/"` — that was a workaround for the popup-blocker problem and it used the wrong (localhost) URL anyway. `openPreview` handles the Simple Browser open natively with the correct forwarded URL. ## Net user experience after this lands Click Launch workbench → **one** Firefox tab opens (VS Code Web). Inside: - welcome.md as an editor tab (via `openFiles`) - Simple Browser editor tab with the workbench rendered inline (via `openPreview`) - Terminal panel labeled "workbench" showing the 🚀 banner + tier logs Single window. No popup blocker. No permission prompt. Same recipe streamlit + the official GitHub Codespaces docs recommend. ## Refs - streamlit/streamlit-example .devcontainer/devcontainer.json — the canonical exemplar of this recipe. - GitHub Codespaces "Customizable Initial Experience" changelog (2022-10-26) — documents `openFiles` + `postAttachCommand` + `onAutoForward: openPreview` as the intended three-key pattern. - microsoft/vscode-remote-try-* — base image version pinning precedent (`1-3.12-bookworm` etc.). Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
3 tasks
fede-kamel
added a commit
that referenced
this pull request
May 12, 2026
…pen fix) (#161) After four iterations (#155, #157, #158, #160), the Codespaces Simple Browser auto-open was still unreliable. The user's symptom: open a fresh codespace, VS Code Web boots, tiers come up, banner prints — but no Simple Browser tab pops with the workbench. Manual click on the URL is still required. ## Root cause `portsAttributes.5173.onAutoForward: "openPreview"` only fires for the user when a VS Code client is **attached at the moment the port binds**. In our setup, `postStartCommand` boots all three tiers *before* the user's VS Code Web has finished attaching to the container. Vite binds on :5173 → no client attached → openPreview silently no-ops. By the time the user shows up, the port-forward event is already past and Simple Browser never opens. This is the timing trap that streamlit-example sidesteps by putting the server itself in `postAttachCommand`, not in `postStartCommand`. With the server in postAttach, the port binds **after** the user is attached, so openPreview's event handler receives the bind and pops Simple Browser. The earlier PR #160 also tried to fix this with an active `code --open-url "vscode://vscode.simpleBrowser.api.open/<url>"` call, but that URI format isn't a valid VS Code Command URI — should be `vscode://command/simpleBrowser.show?<JSON-encoded args>`. ## Fix 1. **Move tier startup from `postStartCommand` into `postAttachCommand`.** Server boots after the user attaches; ports bind with a client present; openPreview reliably fires. 2. **Make tier startup idempotent.** `postAttachCommand` fires on every attach (not just the first), so the script checks whether each port is already listening before launching its tier. Second attach is a no-op for the tiers. 3. **Use the correct Command URI** for the active Simple Browser open: `vscode://command/simpleBrowser.show?<URL-encoded JSON array>`. Belt-and-braces; works even if openPreview's port-bind event misfires for any reason. ## Implementation - New `.devcontainer/workbench-attach.sh` — single entry point that does idempotent tier-boot + Vite-wait + Simple-Browser-open + banner + log-tail. Replaces both `postStart.sh` and `workbench-banner.sh` (deleted). - `devcontainer.json` — `postStartCommand` removed; `postAttachCommand` now points to the new script. ## Why postStartCommand is gone entirely There's nothing for it to do anymore. Container build runs `updateContentCommand` (deps install). User attaches → `postAttachCommand` runs. No work fits between those two events that wouldn't be either too-early (port-bind race) or never-needed. ## Reference - streamlit/streamlit-example .devcontainer/devcontainer.json — the canonical pattern with server-in-postAttach. - VS Code Command URI docs — correct `vscode://command/<id>?<args>` shape. Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three small additions that close the "I clicked the docs button but where's the workbench?" gap a developer hits the first time they launch a Codespace.
The gap
GitHub Codespaces auto-opens VS Code Web. The devcontainer's
5173.onAutoForward: openBrowserOncetries to open a second tab with the workbench UI when Vite binds — but that popup gets silently eaten by Safari and other strict popup blockers, leaving the developer staring at a VS Code editor wondering where the playground is.Three improvements in one PR
.vscode/tasks.json— workspace-open task that fires automatically the moment VS Code opens this workspace (runOn: "folderOpen")..devcontainer/workbench-banner.sh— the script the task runs. Waits for Vite to bind, then prints a clear🚀 locus workbench is readybanner in a dedicated VS Code terminal panel with a ⌘-clickable URL. URL is constructed from$CODESPACE_NAME(set by GitHub) or falls back tolocalhost:5173for local devcontainer runs. Then tails the three tier logs so the panel stays alive..devcontainer/welcome.md— opened automatically by the banner script viacode .devcontainer/welcome.md. A short getting-started doc with the workbench URL, the two-click flow, what's running on each port, and how to restart tiers.Plus a clarifying paragraph in
docs/workbench.md— the "Codespaces — what happens after you click" section now explicitly warns that two browser tabs open (VS Code Web first, then the workbench*-5173.app.github.devonce Vite binds), and that the in-VS-Code banner is the recovery path if the popup blocker eats the second tab.Net effect
Developer clicks Launch workbench → VS Code Web tab opens → within seconds the banner task fires a dedicated terminal panel that says "🚀 workbench is at " → welcome.md opens as an editor tab beside it → forwarded workbench tab also auto-pops unless blocked. Even with the worst popup blocker, the developer has two visible paths to the playground inside their VS Code window.
Related