Skip to content

feat(workbench): in-codespace onboarding — banner, welcome doc, two-tabs explainer#155

Merged
fede-kamel merged 2 commits into
mainfrom
feat/workbench-codespace-onboarding
May 12, 2026
Merged

feat(workbench): in-codespace onboarding — banner, welcome doc, two-tabs explainer#155
fede-kamel merged 2 commits into
mainfrom
feat/workbench-codespace-onboarding

Conversation

@fede-kamel
Copy link
Copy Markdown
Contributor

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: openBrowserOnce tries 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

  1. .vscode/tasks.json — workspace-open task that fires automatically the moment VS Code opens this workspace (runOn: "folderOpen").

  2. .devcontainer/workbench-banner.sh — the script the task runs. Waits for Vite to bind, then prints a clear 🚀 locus workbench is ready banner in a dedicated VS Code terminal panel with a ⌘-clickable URL. URL is constructed from $CODESPACE_NAME (set by GitHub) or falls back to localhost:5173 for local devcontainer runs. Then tails the three tier logs so the panel stays alive.

  3. .devcontainer/welcome.md — opened automatically by the banner script via code .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.dev once 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

…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>
@oracle-contributor-agreement oracle-contributor-agreement Bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label May 12, 2026
@fede-kamel fede-kamel merged commit 91b2ddb into main May 12, 2026
10 checks passed
@fede-kamel fede-kamel deleted the feat/workbench-codespace-onboarding branch May 12, 2026 06:02
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>
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>
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant