Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 7 additions & 7 deletions .github/workflows/studio-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ jobs:
with:
deno-version: v2.x

- name: Setup Node.js (playground vite build)
- name: Setup Node.js (studio-ui vite build)
uses: actions/setup-node@v6
with:
node-version: '24'
Expand Down Expand Up @@ -139,15 +139,15 @@ jobs:
# `npm install` runs `prepare: svelte-kit sync` for each SvelteKit
# package and generates `.svelte-kit/tsconfig.json`, which is what
# `packages/ui/tsconfig.json` extends. `deno install` skips lifecycle
# scripts, so without an explicit sync step the playground vite build
# scripts, so without an explicit sync step the studio-ui vite build
# fails with `failed to resolve "extends":"./.svelte-kit/tsconfig.json"`.
shell: bash
run: |
cd packages/ui && npx svelte-kit sync
cd ../../tools/agent-playground && npx svelte-kit sync
cd ../../apps/studio-ui && npx svelte-kit sync

- name: Build playground static UI
working-directory: tools/agent-playground
- name: Build studio-ui static UI
working-directory: apps/studio-ui
run: npm run build

- name: Import Apple Developer ID certificate (macOS)
Expand Down Expand Up @@ -181,7 +181,7 @@ jobs:
set -euo pipefail
STAGING="dist/${{ matrix.target }}/staging"
# Sign every Mach-O binary in staging with Hardened Runtime so
# notarization passes. atlas/link/playground/webhook-tunnel run JIT
# notarization passes. atlas/link/studio-ui/webhook-tunnel run JIT
# (V8) so they need entitlements for unsigned-executable-memory.
ENTITLEMENTS="$(mktemp -t entitlements.plist).plist"
cat > "$ENTITLEMENTS" <<'PLIST'
Expand Down Expand Up @@ -211,7 +211,7 @@ jobs:
for f in \
"bin/friday" \
"bin/link" \
"bin/playground" \
"bin/studio-ui" \
"bin/webhook-tunnel" \
"friday-launcher" \
"bin/gh" \
Expand Down
4 changes: 1 addition & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
"[json]": { "editor.defaultFormatter": "biomejs.biome" },
"[markdown]": { "editor.defaultFormatter": "denoland.vscode-deno" },
"editor.codeActionsOnSave": { "source.organizeImports.biome": "explicit" },
"eslint.workingDirectories": [
{ "directory": "tools/agent-playground", "changeProcessCWD": true }
],
"eslint.workingDirectories": [{ "directory": "apps/studio-ui", "changeProcessCWD": true }],
"eslint.validate": ["javascript", "typescript", "svelte"]
}
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ version:

```bash
# Deno + TypeScript (core platform)
deno task dev:playground # Daemon (auto-restart) + web playground + link + tunnel
deno task dev:studio-ui # Daemon (auto-restart) + Studio UI + link + tunnel
deno task start # Daemon only, no auto-restart
deno task typecheck # Type check (deno check + svelte-check)
deno task lint # Lint
Expand Down
32 changes: 16 additions & 16 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Friday Platform image: atlasd + link + agent-playground + webhook-tunnel
# Friday Platform image: atlasd + link + studio-ui + webhook-tunnel
#
# Build:
# docker build -t friday-platform .
Expand All @@ -9,17 +9,17 @@
# Ports:
# 18080 atlasd (daemon API) - mapped to container port 8080
# 13100 link (credential/auth service) - mapped to container port 3100
# 15200 agent-playground (web UI) - mapped to container port 5200
# 15200 studio-ui (web UI) - mapped to container port 5200
# 19090 webhook-tunnel - mapped to container port 9090

# ============================================================================
# Stage 1: Deno builder — compile atlas/link binaries & prepare playground
# Stage 1: Deno builder — compile atlas/link binaries & prepare studio-ui
# ============================================================================
FROM denoland/deno:debian-2.7.4 AS deno-builder

WORKDIR /app

# Need Node.js/npm for building @atlas/ui (svelte-package) and the playground.
# Need Node.js/npm for building @atlas/ui (svelte-package) and studio-ui.
RUN apt-get update && apt-get install -y --no-install-recommends \
nodejs npm && \
rm -rf /var/lib/apt/lists/*
Expand All @@ -30,7 +30,7 @@ COPY deno.json deno.lock package.json ./
COPY apps/atlasd/deno.json apps/atlasd/package.json* ./apps/atlasd/
COPY apps/atlas-cli/deno.json apps/atlas-cli/package.json* ./apps/atlas-cli/
COPY apps/link/deno.json apps/link/package.json* ./apps/link/
COPY tools/agent-playground/deno.json tools/agent-playground/package.json ./tools/agent-playground/
COPY apps/studio-ui/deno.json apps/studio-ui/package.json ./apps/studio-ui/
COPY tools/evals/deno.json tools/evals/package.json ./tools/evals/
COPY packages/ ./packages/

Expand All @@ -40,12 +40,12 @@ RUN deno install
# Copy full source (changes frequently but doesn't bust the install cache)
COPY . .

# Build @atlas/ui — the playground imports from dist/ which needs svelte-package
# Build @atlas/ui — studio-ui imports from dist/ which needs svelte-package
WORKDIR /app/packages/ui
RUN npx svelte-kit sync && npx svelte-package -o dist

# Generate .svelte-kit/tsconfig.json for the playground so vite doesn't warn
WORKDIR /app/tools/agent-playground
# Generate .svelte-kit/tsconfig.json for studio-ui so vite doesn't warn
WORKDIR /app/apps/studio-ui
RUN npx svelte-kit sync

WORKDIR /app
Expand Down Expand Up @@ -178,9 +178,9 @@ COPY --from=go-builder /out/webhook-tunnel /usr/local/bin/webhook-tunnel
WORKDIR /app

# ── Copy runtime source for services that can't be compiled ──────────────────
# agent-playground: Vite dev server needs source + node_modules
# studio-ui: Vite dev server needs source + node_modules

# Workspace config (Deno needs these to resolve imports for the playground)
# Workspace config (Deno needs these to resolve imports for studio-ui)
COPY --chown=atlas:atlas --from=deno-builder /app/deno.json /app/deno.lock /app/package.json /app/tsconfig.json /app/reset.d.ts /app/
COPY --chown=atlas:atlas --from=deno-builder /app/types /app/types

Expand All @@ -190,7 +190,7 @@ COPY --chown=atlas:atlas --from=deno-builder /app/types /app/types
RUN node -e " \
const ws = [ \
'./packages/*', \
'./tools/agent-playground' \
'./apps/studio-ui' \
]; \
for (const f of ['/app/deno.json', '/app/package.json']) { \
const c = JSON.parse(require('fs').readFileSync(f, 'utf8')); \
Expand All @@ -199,19 +199,19 @@ RUN node -e " \
require('fs').writeFileSync(f, JSON.stringify(c, null, 2) + '\n'); \
}" && chown atlas:atlas /app/deno.json /app/package.json /app/deno.lock

# Runtime tools (playground needs source + svelte-kit)
COPY --chown=atlas:atlas --from=deno-builder /app/tools/agent-playground /app/tools/agent-playground
# Runtime app source (studio-ui needs source + svelte-kit)
COPY --chown=atlas:atlas --from=deno-builder /app/apps/studio-ui /app/apps/studio-ui

# Shared packages (playground imports @atlas/ui etc.)
# Shared packages (studio-ui imports @atlas/ui etc.)
COPY --chown=atlas:atlas --from=deno-builder /app/packages /app/packages

# Agent definitions
COPY --chown=atlas:atlas --from=deno-builder /app/.agents /app/.agents

# node_modules — only needed for the playground (vite, svelte)
# node_modules — only needed for studio-ui (vite, svelte)
COPY --chown=atlas:atlas --from=deno-builder /app/node_modules /app/node_modules

# Deno cache — only what the playground needs at runtime.
# Deno cache — only what studio-ui needs at runtime.
# The compiled binaries (atlas, link, webhook-tunnel) are self-contained.
COPY --chown=atlas:atlas --from=deno-builder /deno-dir /deno-dir
# Fix /deno-dir top-level dir ownership (base image creates it as deno:deno,
Expand Down
2 changes: 1 addition & 1 deletion NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This product includes software developed by third parties.
Friday Studio ships several artifacts, each of which bundles a different set of
upstream dependencies:

- Atlas daemon, CLI, and web playground (Deno + npm + JSR packages)
- Atlas daemon, CLI, and Studio UI (Deno + npm + JSR packages)
- Friday Launcher, pty-server, webhook-tunnel (Go modules)
- Studio Installer (Rust crates via Cargo / Tauri)

Expand Down
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ their machine.

Two surfaces, one runtime:

- **Chat in the playground.** Friday picks up your installed skills, MCP
- **Chat in Studio UI.** Friday picks up your installed skills, MCP
servers, memory, and OAuth credentials, and actually drives your tools
instead of describing what it would do.
- **Run autonomously.** Capture the pattern in a `workspace.yml`, bind it
Expand All @@ -32,7 +32,7 @@ without wiring queues, secret stores, schedulers, MCP plumbing, and
provider clients from scratch every time.

> **Prefer the packaged version?** **[hellofriday.ai](https://hellofriday.ai)**
> ships the same daemon and playground as a one-click installer for macOS
> ships the same daemon and Studio UI as a one-click installer for macOS
> with the launcher, dependencies, and tray UI bundled. The
> rest of this README is for working in-tree.

Expand All @@ -41,10 +41,10 @@ provider clients from scratch every time.
| | What it is | When you use it |
| --- | --- | --- |
| **`atlasd` (daemon)** | Headless runtime — HTTP API on `:8080`, workspace lifecycle, signal router, session state, JetStream message bus. | Production. CI. Anything you'd `systemd`-ify. |
| **Agent Playground** | SvelteKit web UI on `:5200` — chat with Friday, author and run agents, inspect every session step-by-step, manage skills/MCP servers/schedules/memory/credentials, browse the workspace marketplace. | Day-to-day. The playground is what you actually look at. |
| **Studio UI** | SvelteKit web UI on `:5200` — chat with Friday, author and run agents, inspect every session step-by-step, manage skills/MCP servers/schedules/memory/credentials, browse the workspace marketplace. | Day-to-day. Studio UI is what you actually look at. |

The desktop installer ships both behind a tray icon. In-tree, `deno task
dev:playground` runs both side by side with hot reload.
dev:studio-ui` runs both side by side with hot reload.

## Quickstart

Expand All @@ -59,7 +59,7 @@ handles the rest.

| Tool | Min | Why |
| --- | --- | --- |
| [Node.js](https://nodejs.org/) | `24+` | Playground runs under Vite via `npx`; `@atlas/ui` builds with `svelte-package`. Manage via fnm/volta/nvm — auto-installing system Node clobbers project pins. |
| [Node.js](https://nodejs.org/) | `24+` | Studio UI runs under Vite via `npx`; `@atlas/ui` builds with `svelte-package`. Manage via fnm/volta/nvm — auto-installing system Node clobbers project pins. |
| [git](https://git-scm.com/) | any recent | — |

**`setup-dev-env.sh` handles these — installs if missing or below min, otherwise keeps yours:**
Expand Down Expand Up @@ -111,13 +111,13 @@ The example file documents every variable the daemon reads — provider keys,
proxies, OAuth/GitHub App credentials, integration tokens. The minimum to
run a real agent is one LLM provider key.

### 3. Run the playground (recommended)
### 3. Run Studio UI (recommended)

One command, four processes — daemon, link, playground, and webhook tunnel —
One command, four processes — daemon, link, Studio UI, and webhook tunnel —
all with hot reload:

```bash
deno task dev:playground
deno task dev:studio-ui
```

Open <http://localhost:5200> and the sidebar gives you everything: bundled
Expand All @@ -138,7 +138,7 @@ deno task atlas daemon stop

### Just chat with it

Open the playground at <http://localhost:5200>. Type:
Open Studio UI at <http://localhost:5200>. Type:

> *Find every unread email from my team that's waiting on a reply, summarize what each is asking, and draft responses.*

Expand Down Expand Up @@ -218,9 +218,9 @@ Browse [`friday-studio-examples`](https://github.com/friday-platform/friday-stud
for `github-digest`, `competitive-monitor`, `daily-operating-memo`,
`jira-bugfix-bitbucket`, and others.

## Agent Playground
## Studio UI

`deno task dev:playground` opens the playground at <http://localhost:5200>.
`deno task dev:studio-ui` opens Studio UI at <http://localhost:5200>.
It's the same Svelte app the desktop installer ships — production UI, not
a debug widget.

Expand Down Expand Up @@ -253,8 +253,8 @@ deno task sim "..." --stop-at=fsm # blueprint + FSM compile
deno task sim "..." --real # execute with real MCP agents
```

Artifacts land in `runs/workspaces/<timestamp>-<slug>/` — replay them in the
playground's **Workspaces / History** tab.
Artifacts land in `runs/workspaces/<timestamp>-<slug>/` — replay them in
Studio UI's **Workspaces / History** tab.

## Common commands

Expand Down Expand Up @@ -285,7 +285,7 @@ Want it all in containers?
docker compose up
```

Brings up the daemon, playground, link credential service, PTY server, and
Brings up the daemon, Studio UI, link credential service, PTY server, and
webhook tunnel. Ports default to `1xxxx` to avoid host collisions — see
[`docker-compose.yml`](docker-compose.yml).

Expand All @@ -299,11 +299,11 @@ apps/
ledger/ # Resource & activity storage service
studio-installer/ # Tauri desktop app — tray, daemon supervisor,
# autostart. The hellofriday.ai download.
studio-ui/ # SvelteKit web UI — Studio UI (production frontend)
packages/ # @atlas/* libraries — core, agent-sdk, config,
# fsm-engine, llm, logger, mcp, memory, skills,
# storage, workspace, signals, jetstream, …
tools/
agent-playground/ # Web client (SvelteKit) — production UI
evals/ # Agent eval harness
friday-launcher/ # System tray launcher + daemon supervisor (Go)
pty-server/ # WebSocket → PTY shell bridge (Go)
Expand Down
4 changes: 2 additions & 2 deletions THIRD_PARTY_LICENSES.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Third-Party Licenses

This file lists every third-party dependency bundled into a shipped Friday
Studio artifact (the daemon, CLI, web playground, Friday Launcher,
Studio artifact (the daemon, CLI, Studio UI, Friday Launcher,
webhook tunnel, and Studio Installer). It is generated automatically by
[`scripts/generate-third-party-licenses.sh`](scripts/generate-third-party-licenses.sh).

Expand Down Expand Up @@ -834,7 +834,7 @@ Bundled into: `apps/studio-installer` (Tauri installer binary).

## npm / JSR packages

Bundled into: the Atlas daemon, CLI, web playground, and any compiled
Bundled into: the Atlas daemon, CLI, Studio UI, and any compiled
Deno binaries. Inventory is taken from `deno.lock`.

| Package | Version | Source |
Expand Down
16 changes: 8 additions & 8 deletions apps/atlas-cli/src/cli/commands/agent/exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { parseSSEStream } from "@atlas/utils/sse";
import { define } from "gunshi";
import { errorOutput } from "../../../utils/output.ts";

const DEFAULT_PLAYGROUND_URL = "http://localhost:5200";
const DEFAULT_STUDIO_UI_URL = "http://localhost:5200";

/**
* Renders a single SSE event to stdout in human-readable format.
Expand Down Expand Up @@ -94,7 +94,7 @@ function parseEnvArgs(envArgs: string | undefined): Record<string, string> | und

export const execCommand = define({
name: "exec",
description: "Execute an agent via the playground and stream results",
description: "Execute an agent via Studio UI and stream results",
args: {
agent: { type: "positional", description: "Agent ID to execute", required: true },
input: {
Expand All @@ -104,7 +104,7 @@ export const execCommand = define({
required: true,
},
json: { type: "boolean", description: "Output raw SSE events as NDJSON", default: false },
url: { type: "string", description: `Playground URL (default: ${DEFAULT_PLAYGROUND_URL})` },
url: { type: "string", description: `Studio UI URL (default: ${DEFAULT_STUDIO_UI_URL})` },
env: {
type: "string",
short: "e",
Expand All @@ -125,34 +125,34 @@ export const execCommand = define({
process.exit(1);
}

const playgroundUrl = ctx.values.url ?? DEFAULT_PLAYGROUND_URL;
const studioUIUrl = ctx.values.url ?? DEFAULT_STUDIO_UI_URL;
const env = parseEnvArgs(ctx.values.env);
const jsonMode = ctx.values.json;

const body = JSON.stringify({ agentId, input, env });

let response: Response;
try {
response = await fetch(`${playgroundUrl}/api/execute`, {
response = await fetch(`${studioUIUrl}/api/execute`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body,
});
} catch {
errorOutput(
`Could not connect to playground at ${playgroundUrl}. Is it running? (deno task playground)`,
`Could not connect to Studio UI at ${studioUIUrl}. Is it running? (deno task studio-ui)`,
);
process.exit(1);
}

if (!response.ok) {
const text = await response.text();
errorOutput(`Playground returned ${response.status}: ${text}`);
errorOutput(`Studio UI returned ${response.status}: ${text}`);
process.exit(1);
}

if (!response.body) {
errorOutput("No response body from playground");
errorOutput("No response body from Studio UI");
process.exit(1);
}

Expand Down
2 changes: 1 addition & 1 deletion apps/atlas-cli/src/cli/commands/agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ export const agentCommand = define({
console.log(" list, ls List agents");
console.log(" describe, show, get View agent details");
console.log(" register, r Register an SDK agent");
console.log(" exec, x Execute an agent via playground");
console.log(" exec, x Execute an agent via Studio UI");
},
});
2 changes: 2 additions & 0 deletions apps/atlasd/src/migrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import { migration as m_20260505_120000_elicitations_bootstrap } from "./m_20260
import { migration as m_20260507_120000_drop_scratchpad_kv } from "./m_20260507_120000_drop_scratchpad_kv.ts";
import { migration as m_20260511_110800_provision_workspace_members } from "./m_20260511_110800_provision_workspace_members.ts";
import { migration as m_20260511_120000_cleanup_userid_as_name } from "./m_20260511_120000_cleanup_userid_as_name.ts";
import { migration as m_20260513_013700_rename_playground_env_vars } from "./m_20260513_013700_rename_playground_env_vars.ts";

/**
* Static manifest. Ordered by id ascending — keep new entries in
Expand Down Expand Up @@ -88,6 +89,7 @@ const MIGRATIONS: readonly Migration[] = [
m_20260507_120000_drop_scratchpad_kv,
m_20260511_110800_provision_workspace_members,
m_20260511_120000_cleanup_userid_as_name,
m_20260513_013700_rename_playground_env_vars,
];

/**
Expand Down
Loading
Loading