Reach a hosted workbench's web UI
Goal: Browse a Web-mode workbench in your workspace — hosted HTML + interactive JS at a stable per-workbench URL, gated by your workspace access rights.
Prerequisites
- A hosted workbench with WebMode enabled — see Install a workbench from source.
- A Bearer JWT (or a valid workspace session cookie) with the
Workspace.Workbench.Hostaccess right. - A browser or any HTTP client.
Your workspace URL
Throughout this guide, replace <your-workspace-url> with your product host:
- Open Industrial:
https://www.openindustrial.co - Fathym OpenX:
https://openx.fathym.com - Local development: e.g.
http://localhost:8080
Once a workbench is hosted with WebMode, its browser URL is:
<your-workspace-url>/oi-api/workbenches/{APISlug}/Web/
For example, the ui-sample workbench (from fathym-deno/ui-workbench) on Open Industrial is at https://www.openindustrial.co/oi-api/workbenches/ui-sample/Web/.
Every path under .../Web/{route} is forwarded to the container's fetch handler — no author-declared routing at the platform layer. Your workbench author decides which paths exist and what each responds with.
What the workbench author writes
WebMode is a thin Deno.serve wrapper. The author writes a fetch handler:
import { WebMode, Workbench } from '@fathym/fai/workbenches';
async function serve(req: Request): Promise<Response> {
const url = new URL(req.url);
if (url.pathname === '/') {
return new Response('<h1>UI Workbench</h1>', {
headers: { 'Content-Type': 'text/html' },
});
}
return new Response('Not Found', { status: 404 });
}
export default Workbench('ui-sample')
.Modes({ Web: WebMode({ handler: serve }) });
The handler receives every request except GET /health (reserved for OpenX's SOP readiness probe). Any framework works — plain fetch handlers, Fresh, Hono, whatever the author chooses.
Option 1: browser
The simplest consumer. Browse the URL directly in a browser tab with an active workspace session:
<your-workspace-url>/oi-api/workbenches/ui-sample/Web/
The workspace session cookie is picked up as the auth path; the proxy validates Workspace.Workbench.Host and forwards to the container.
The workspace API Explorer → "Hosted Workbench Web" tab surfaces a per-workbench card with an "Open in new tab" button — the fastest way to jump into a hosted workbench without hand-typing the URL.
Option 2: programmatic fetch
Same URL, same auth, no browser:
const res = await fetch(
'<your-workspace-url>/oi-api/workbenches/ui-sample/Web/products',
{
method: 'GET',
headers: { 'Authorization': `Bearer ${jwt}` },
},
);
const html = await res.text();
Works for headless integrations (e.g. a backend that renders + emails a Web workbench's page as a report).
Composing with other workbenches
Web workbenches often consume data from other workspace workbenches. See Workbench composition (Consumes) for the primitive that wires cross-workbench URLs into the consumer container's environment.
The mode-agnostic surface
WebMode, APIMode, and MCPMode all run on the same OpenX hosting substrate — per-mode container behind the workspace access-gated proxy. Enable multiple modes on the same workbench and the same source ships as a browser UI, a REST API, and an MCP server simultaneously. Which modes you enable picks the client shapes; the platform stays the same.
Sample workbench
fathym-deno/ui-workbench — public reference implementation. Two HTML routes (/ home + /products reads a consumed API workbench) wired into .Modes({ Web: WebMode({ handler: serve }) }). The README.md walks through the local run, deploy via OpenX (including the Consumes step for the /products route), and known caveats.
Mirror it for your own Web workbenches — same 3-file layout, swap in your own handler.
Auth + governance
Same governance model as the MCP + API modes:
- Authentication — Bearer JWT OR workspace session cookie required on every request.
- Authorization — the caller must hold
Workspace.Workbench.Host. - Audit — every proxied request is logged with caller, workbench APISlug, method, path, and timestamp.
- Isolation — the Web container runs alongside (and isolated from) any other enabled mode containers for the same workbench.
Troubleshooting
| Issue | Solution |
|---|---|
Browser gets 401 Unauthorized | Session expired or missing the Workspace.Workbench.Host right. Refresh the session or confirm your access rights. |
| Page renders but a fetch inside it fails | If the workbench's page makes browser-side requests back to /oi-api/workbenches/..., those go through the proxy with the same session credentials. Missing rights or expired session show as 401. |
Container returns 503 on first request | Cold-start. First browse takes 5–15s; subsequent are fast. Set minReplicas: 1 on the workbench Hosting tab for always-on. |
| Static assets 404 | The author's handler is responsible for static asset routing. Check the workbench source for the Content-Type: image/* / text/css / etc. branches. |
| Consumed workbench URL not injected | See Composition for the Consumes declaration + inspector configuration. |
Next steps
| If you want to... | Go to... |
|---|---|
| Install another workbench | Install a workbench from source → |
| Declare dependencies on other workbenches | Composition (Consumes) → |
| Call a hosted workbench's tools via REST | API access → |
| Connect Claude / Cursor to a hosted MCP workbench | MCP access → |
| Understand the mode model | Workbenches overview → |