Skip to content

Move agent-playground → apps/studio-ui#293

Open
ljagiello wants to merge 6 commits into
mainfrom
worktree-jazzy-skipping-jellyfish
Open

Move agent-playground → apps/studio-ui#293
ljagiello wants to merge 6 commits into
mainfrom
worktree-jazzy-skipping-jellyfish

Conversation

@ljagiello
Copy link
Copy Markdown
Contributor

Summary

Renames the SvelteKit web UI from tools/agent-playground to apps/studio-ui and its runtime identifiers from playground to studio-ui.

  • Package: @atlas/agent-playground@atlas/studio-ui
  • Tasks: deno task playgrounddeno task studio-ui; dev:playground[:stable]dev:studio-ui[:stable]
  • Runtime contract: binary playgroundstudio-ui; env PLAYGROUND_PORT/HOSTSTUDIO_UI_PORT/HOST; FRIDAY_PORT_PLAYGROUNDFRIDAY_PORT_STUDIO_UI; log prefix [playground][studio-ui]
  • Launcher (Go): service name + playgroundURLstudioUIURL + 4 test files
  • Installer (Rust + Svelte): Tauri command playground_urlstudio_ui_url; serde field playground_healthystudio_ui_healthy; constants, store, helpers
  • Infra: Dockerfile, docker/run-platform.sh, studio-build.yml (incl. critical bin/playgroundbin/studio-ui in codesigning loop), scripts/build-studio.ts, scripts/dev-watcher.ts, .vscode/settings.json
  • Docs: README.md, CONTRIBUTING.md, NOTICE, THIRD_PARTY_LICENSES.md, skill markdown
  • atlas-cli: agent exec error messages + DEFAULT_PLAYGROUND_URLDEFAULT_STUDIO_UI_URL

Left intact (internal identifiers, semantically distinct from binary/service name):

  • "playground" workspaceId magic string
  • PlaygroundContextAdapter class + PlaygroundContextOpts interface
  • Internal "the playground" comments
  • TanStack query keys, test fixtures, QA scenario locals

Test plan

  • deno install
  • deno task sync:svelte
  • deno task typecheck — 0 errors
  • deno run -A npm:@biomejs/biome check — 0 errors
  • deno lint
  • npm run build in apps/studio-ui — vite build succeeds
  • deno compile of apps/studio-ui/static-server.ts — produces working binary; boots with [studio-ui] log prefix on :5200
  • go build ./...
  • go test ./... in tools/friday-launcher
  • cargo check --tests in apps/studio-installer/src-tauri
  • CI green (studio-build.yml's codesign loop now references bin/studio-ui)

Renames the SvelteKit web UI from `tools/agent-playground` to `apps/studio-ui` and
its runtime identifiers from `playground` to `studio-ui`. The package is now
`@atlas/studio-ui`, the dev task is `deno task studio-ui` (orchestrated by
`dev:studio-ui`), the compiled binary is `bin/studio-ui`, env vars are
`STUDIO_UI_PORT`/`STUDIO_UI_HOST` / `FRIDAY_PORT_STUDIO_UI`, and the log prefix
is `[studio-ui]`. Launcher (Go), installer (Rust + Svelte), Dockerfile, GH
Actions workflow, build/dev scripts, atlas-cli `agent exec`, docs, and skill
markdown all updated in lockstep.

Internal names left intact per design: the `"playground"` workspaceId magic
string, `PlaygroundContextAdapter` class, internal "the playground" comments,
TanStack query keys, and QA scenario locals.

Verified: `deno task typecheck`, `biome check`, `deno lint`, `npm run build`
(vite), `deno compile` (binary boots with [studio-ui] log prefix on :5200),
`go build ./...`, `go test ./...` (friday-launcher), `cargo check --tests`
(studio-installer).
@ljagiello ljagiello requested a review from Vpr99 as a code owner May 13, 2026 01:19
ljagiello added 5 commits May 12, 2026 18:20
The previous commit captured the file moves and config rewrites but missed
the source edits I'd made after `git mv` — they were in the working tree but
never `git add`ed.

This commit lands the rest of the rename: studio-installer Rust/Svelte source
(Tauri command playground_url → studio_ui_url, serde field, constants), the
Go launcher's playgroundURL → studioUIURL, atlas-cli `agent exec` user-facing
strings, docs (README, CONTRIBUTING, NOTICE, THIRD_PARTY_LICENSES, skill
markdown), Dockerfile, run-platform.sh, dev-watcher, build-studio, and the
critical bin/playground → bin/studio-ui in .github/workflows/studio-build.yml
that the codesign step iterates over.
Svelte derives its CSS scope hash from the component's source path. Moving
`tools/agent-playground` → `apps/studio-ui` changed every `.svelte` component's
scope hash, which only surfaced for components with snapshot-based tests.
validation-pill-row is the only one in the repo with a `toMatchSnapshot`
on rendered HTML; its 5 snapshots needed regenerating against the new path.

The remaining 5979 tests pass without changes.
After the agent-playground → studio-ui rename, the launcher reads
FRIDAY_PORT_STUDIO_UI for the port override. Existing installs have
FRIDAY_PORT_PLAYGROUND written to ~/.friday/local/.env (by the installer
at 15200, or by users at custom values for multi-instance setups). Without
a migration, customised ports silently revert to the default on upgrade.

This migration rewrites the legacy key on first daemon boot:
- .env missing → no-op
- only PLAYGROUND → rewrite to STUDIO_UI, value preserved
- only STUDIO_UI → no-op
- both → drop legacy line (new key wins at the launcher)

Idempotent via the standard JetStream migration ledger. Line-by-line
rewrite preserves comments, blank lines, and all unrelated keys.

Tests cover all 4 branches + quoted values, surrounding context
preservation, comment-key disambiguation, and second-pass idempotency.
Extends the migration to defensively rewrite all three renamed env vars:

  FRIDAY_PORT_PLAYGROUND  → FRIDAY_PORT_STUDIO_UI
  PLAYGROUND_PORT         → STUDIO_UI_PORT
  PLAYGROUND_HOST         → STUDIO_UI_HOST

The launcher normally injects PLAYGROUND_PORT/HOST into the spawned
binary's process env at boot, so they don't usually live on disk —
but a user could have set them in ~/.friday/local/.env for debugging
or a custom dev setup. Better to migrate them and be wrong than skip
them and have a user silently lose their override.

Each pair is applied independently: a file with FRIDAY_PORT_PLAYGROUND
set but no PLAYGROUND_PORT only sees the first key rewritten.

Tests cover each pair in isolation, the multi-pair case, and the
selective case where only some legacy keys are present.
Real bug: the installer runs `ensure_platform_env_vars` BEFORE `migrate`
(per apps/studio-installer/src/steps/Extract.svelte). On upgrade, the
installer seeds FRIDAY_PORT_STUDIO_UI=15200 (default) into the .env
because the key is missing, then migrate sees both legacy + new and
the old "drop legacy" branch silently lost any custom value the user
had set on FRIDAY_PORT_PLAYGROUND.

Fix: when both keys are present, the LEGACY value wins. Drop the
new-key line (just an installer default), rewrite the legacy line to
use the new key name. User customisations now survive the upgrade.

Behaviour applies uniformly to all three pairs. FRIDAY_PORT_* is the
installer-managed case where this matters most; PLAYGROUND_PORT/HOST
follow the same rule for consistency (and "user set the legacy
explicitly, then also added the new key" almost certainly means they
wanted the legacy value preserved).

Tests updated: the both-present branch now asserts the legacy value
survives, with an additional test that confirms line ordering is
preserved when the new-key line is removed from elsewhere in the file.
@Vpr99
Copy link
Copy Markdown
Contributor

Vpr99 commented May 13, 2026

Two pre-existing footguns this rename surfaces — not blocking this PR, but worth a follow-up:

1. apps/atlasd/routes/agents/run.ts:149 — orphaned fallback string

sessionContext: { id: sessionId, workspaceId: workspaceId ?? "playground" },

When callers omit workspaceId, the session context gets "playground". That worked when "playground" was the name of the app; now it's a magic literal pointing at nothing. Either pick an honest default ("studio-ui", "ephemeral") or drop the fallback if call sites always supply one.

2. apps/studio-ui/src/lib/upload.ts:92 — hardcoded workspaceId that fails authz

formData.set("workspaceId", "playground");

The daemon's upload route (apps/atlasd/routes/artifacts.ts:964-966) calls requireWorkspaceMember(c, workspaceId) whenever workspaceId is set, which 403s unless a workspace literally named "playground" exists with a membership row for the caller. Verified this on main — predates the rename. Either the caller needs to thread the real workspaceId through, or the daemon needs an explicit "no workspace" path for ephemeral uploads.

Both share the same root cause ("playground" as a magic workspace identifier), so a single follow-up could address them together.

@basedfriday
Copy link
Copy Markdown
Collaborator

Targeted for 0.1.9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants