Adds an opt-in workbench-styled left rail (256px, fixed-left) on top of the existing chat sidebar so open-webui visually appears embedded inside swept-workbench.
Activated by setting `WORKBENCH_URL` env var; backend exposes it via `/api/config`, frontend `loader.js` fetches it and injects the shell DOM. When unset, vanilla open-webui behavior is preserved.
Stays inside the established minimal-fork pattern from swept-rebrand (#5) and the light-mode/font fix (#7) — only `static/static/*` + a one-field passthrough in `env.py` / `main.py`. Zero Svelte source edits.
What's in the shell
Logo: Swept wordmark (gradient mark + currentColor wordmark) inlined as SVG.
Nav: Chat (active) / Governance / Evaluations / Supervision / Knowledge — non-Chat items link to `${WORKBENCH_URL}/` with `target="_self"` so the embedded illusion holds.
Bottom: Settings → `${WORKBENCH_URL}/settings`.
Lucide icon paths copied verbatim from current workbench (older Lucide paths, e.g. `message-square`, render with a smaller bbox and looked visibly off — see d2f6f for path-by-path comparison).
`html.swept-shell-active aside[data-state]` (the existing chat sidebar's outer fixed container, see `Sidebar.svelte` line ~996) gets `left: 16rem !important` — chat sidebar's own resize math (localStorage `sidebarWidth`) is untouched.
Hidden below `lg` breakpoint so mobile is unaffected.
Why two copies of custom.css/loader.js?
`static/static/` is what Vite copies to `build/static/` — served at SPA paths but NOT at `/static/*`.
`backend/open_webui/static/` is `STATIC_DIR` and is what FastAPI's `/static/` mount actually serves (`main.py` line ~2765). The SwagW rebrand commits also have this dual setup; merging without the mirror means the rebrand silently doesn't ship in fresh container builds.
Test plan
Set `WORKBENCH_URL=http://localhost:3004` (or other workbench URL), restart container, hit `/api/config` — confirm `workbench_url` field present.
Open the app — leftmost 256px column shows Swept wordmark + nav; Chat highlighted blue; existing chat sidebar starts at `left: 256px`.
Click any non-Chat nav item — same-tab navigation to `${WORKBENCH_URL}/`.
Toggle dark mode — shell flips via `html.dark` selectors.
Mobile (<1024px) — shell hidden, only the existing chat sidebar shows.
`unset WORKBENCH_URL` — shell never mounts, layout reverts to vanilla.
Pixel-checked icon size, font weight, font smoothing, and stroke width match swept-workbench's native sidebar.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.
## 📋 Pull Request Information
**Original PR:** https://github.com/open-webui/open-webui/pull/24388
**Author:** [@l3aconator](https://github.com/l3aconator)
**Created:** 5/5/2026
**Status:** ❌ Closed
**Base:** `main` ← **Head:** `feat/workbench-shell`
---
### 📝 Commits (10+)
- [`a818db3`](https://github.com/open-webui/open-webui/commit/a818db3deef5bc6fbb442d662d5c0b8c30c44c0c) Enable 4GB Node heap for frontend build
- [`82e8b5a`](https://github.com/open-webui/open-webui/commit/82e8b5adf7a73deffbe1e497432164b988d34888) Add /approve PR bot workflow
- [`653eb9f`](https://github.com/open-webui/open-webui/commit/653eb9fdde51429331dd7e5d7cb4d5eca3fa9c3c) Merge pull request #1 from swept-ai/fix/dockerfile-node-heap-size
- [`1af5ad9`](https://github.com/open-webui/open-webui/commit/1af5ad9ab1d4f125e31666c4815a0719fc8c36c8) Merge pull request #2 from swept-ai/chore/pr-approve-bot
- [`ed9d688`](https://github.com/open-webui/open-webui/commit/ed9d68834e1d657583f0bf028a38244b7b6ad992) Add CLAUDE.md to orient agents in this repo
- [`c568e61`](https://github.com/open-webui/open-webui/commit/c568e6197e95bcb9006d320a60a94a2711e86c66) Merge branch 'open-webui:main' into main
- [`878fad1`](https://github.com/open-webui/open-webui/commit/878fad132b5f9b94a0c3f52d6a595662cafde53e) Merge pull request #3 from swept-ai/docs/claude-md
- [`78a83e3`](https://github.com/open-webui/open-webui/commit/78a83e3cf475e212275b6553685e150dad39dcdf) Fix frontend build CI heap and remove unused release workflows
- [`cbbd2e5`](https://github.com/open-webui/open-webui/commit/cbbd2e57ca3b875471edda2dc8605297df377685) Apply prettier formatting to CLAUDE.md
- [`0a7ddab`](https://github.com/open-webui/open-webui/commit/0a7ddabab795014e164cbd51221cb993878c12bf) Merge pull request #4 from swept-ai/ci/fix-frontend-build-and-prune-workflows
### 📊 Changes
**56 files changed** (+1929 additions, -1091 deletions)
<details>
<summary>View changed files</summary>
📝 `.env.example` (+15 -1)
➖ `.github/workflows/build-release.yml` (+0 -61)
➖ `.github/workflows/docker-build.yaml` (+0 -917)
📝 `.github/workflows/format-build-frontend.yaml` (+2 -0)
➕ `.github/workflows/pr-approve-bot.yml` (+76 -0)
➖ `.github/workflows/release-pypi.yml` (+0 -36)
📝 `.gitignore` (+6 -1)
➕ `CLAUDE.md` (+71 -0)
📝 `Dockerfile` (+1 -1)
📝 `backend/open_webui/env.py` (+2 -0)
📝 `backend/open_webui/main.py` (+2 -0)
📝 `backend/open_webui/static/custom.css` (+286 -0)
📝 `backend/open_webui/static/loader.js` (+207 -0)
📝 `docker-compose.yaml` (+10 -0)
➕ `docs/integrations/vertex-ai.md` (+220 -0)
➕ `plugins/functions/README.md` (+78 -0)
➕ `plugins/functions/vertex_chat.py` (+268 -0)
➕ `scripts/vertex-impersonate.sh` (+79 -0)
📝 `src/app.css` (+10 -4)
📝 `src/app.html` (+1 -1)
_...and 36 more files_
</details>
### 📄 Description
## Summary
- Adds an opt-in workbench-styled left rail (256px, fixed-left) on top of the existing chat sidebar so open-webui visually appears embedded inside swept-workbench.
- Activated by setting \`WORKBENCH_URL\` env var; backend exposes it via \`/api/config\`, frontend \`loader.js\` fetches it and injects the shell DOM. When unset, vanilla open-webui behavior is preserved.
- Stays inside the established minimal-fork pattern from swept-rebrand (#5) and the light-mode/font fix (#7) — only \`static/static/*\` + a one-field passthrough in \`env.py\` / \`main.py\`. Zero Svelte source edits.
## What's in the shell
- Logo: Swept wordmark (gradient mark + currentColor wordmark) inlined as SVG.
- Nav: Chat (active) / Governance / Evaluations / Supervision / Knowledge — non-Chat items link to \`\${WORKBENCH_URL}/<route>\` with \`target=\"_self\"\` so the embedded illusion holds.
- Bottom: Settings → \`\${WORKBENCH_URL}/settings\`.
- Lucide icon paths copied verbatim from current workbench (older Lucide paths, e.g. \`message-square\`, render with a smaller bbox and looked visibly off — see d2f6f for path-by-path comparison).
## How it integrates with the existing chat sidebar
- \`html.swept-shell-active body\` gets \`padding-left: 16rem\`.
- \`html.swept-shell-active aside[data-state]\` (the existing chat sidebar's outer fixed container, see \`Sidebar.svelte\` line ~996) gets \`left: 16rem !important\` — chat sidebar's own resize math (localStorage \`sidebarWidth\`) is untouched.
- Hidden below \`lg\` breakpoint so mobile is unaffected.
## Why two copies of custom.css/loader.js?
- \`static/static/*\` is what Vite copies to \`build/static/*\` — served at SPA paths but NOT at \`/static/*\`.
- \`backend/open_webui/static/*\` is \`STATIC_DIR\` and is what FastAPI's \`/static/*\` mount actually serves (\`main.py\` line ~2765). The SwagW rebrand commits also have this dual setup; merging without the mirror means the rebrand silently doesn't ship in fresh container builds.
## Test plan
- [x] Set \`WORKBENCH_URL=http://localhost:3004\` (or other workbench URL), restart container, hit \`/api/config\` — confirm \`workbench_url\` field present.
- [x] Open the app — leftmost 256px column shows Swept wordmark + nav; Chat highlighted blue; existing chat sidebar starts at \`left: 256px\`.
- [x] Click any non-Chat nav item — same-tab navigation to \`\${WORKBENCH_URL}/<route>\`.
- [x] Toggle dark mode — shell flips via \`html.dark\` selectors.
- [x] Mobile (<1024px) — shell hidden, only the existing chat sidebar shows.
- [x] \`unset WORKBENCH_URL\` — shell never mounts, layout reverts to vanilla.
- [x] Pixel-checked icon size, font weight, font smoothing, and stroke width match swept-workbench's native sidebar.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---
<sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 Pull Request Information
Original PR: https://github.com/open-webui/open-webui/pull/24388
Author: @l3aconator
Created: 5/5/2026
Status: ❌ Closed
Base:
main← Head:feat/workbench-shell📝 Commits (10+)
a818db3Enable 4GB Node heap for frontend build82e8b5aAdd /approve PR bot workflow653eb9fMerge pull request #1 from swept-ai/fix/dockerfile-node-heap-size1af5ad9Merge pull request #2 from swept-ai/chore/pr-approve-boted9d688Add CLAUDE.md to orient agents in this repoc568e61Merge branch 'open-webui:main' into main878fad1Merge pull request #3 from swept-ai/docs/claude-md78a83e3Fix frontend build CI heap and remove unused release workflowscbbd2e5Apply prettier formatting to CLAUDE.md0a7ddabMerge pull request #4 from swept-ai/ci/fix-frontend-build-and-prune-workflows📊 Changes
56 files changed (+1929 additions, -1091 deletions)
View changed files
📝
.env.example(+15 -1)➖
.github/workflows/build-release.yml(+0 -61)➖
.github/workflows/docker-build.yaml(+0 -917)📝
.github/workflows/format-build-frontend.yaml(+2 -0)➕
.github/workflows/pr-approve-bot.yml(+76 -0)➖
.github/workflows/release-pypi.yml(+0 -36)📝
.gitignore(+6 -1)➕
CLAUDE.md(+71 -0)📝
Dockerfile(+1 -1)📝
backend/open_webui/env.py(+2 -0)📝
backend/open_webui/main.py(+2 -0)📝
backend/open_webui/static/custom.css(+286 -0)📝
backend/open_webui/static/loader.js(+207 -0)📝
docker-compose.yaml(+10 -0)➕
docs/integrations/vertex-ai.md(+220 -0)➕
plugins/functions/README.md(+78 -0)➕
plugins/functions/vertex_chat.py(+268 -0)➕
scripts/vertex-impersonate.sh(+79 -0)📝
src/app.css(+10 -4)📝
src/app.html(+1 -1)...and 36 more files
📄 Description
Summary
What's in the shell
How it integrates with the existing chat sidebar
Why two copies of custom.css/loader.js?
Test plan
🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.