- name
- threadlight-workspace-ui
- description
- Generate a curated, framework-agnostic workspace UI reference for a threadlight process — case-list / inbox / dashboard / console / kanban / map shape with detail pane, action toolbar, audit viewer. Reads spec § 8b Human Interaction (Workspace UX) and produces ONE reference implementation the customer can rebuild in their preferred framework. USE FOR: workspace UI, case management UI, agent operator console, case list with detail pane, action toolbar, audit viewer, threadlight workspace, demo workspace, operator dashboard, add workspace to Kratos export. DO NOT USE FOR: experience.html cinematic (use threadlight-design), Teams Adaptive Cards (use threadlight-hitl-patterns), real-time chat UI, framework-specific scaffolds (we ship pattern, not framework).
- metadata
- {"version":"1.1.1"}
# Threadlight Workspace UI
## Presenter-ready business journey
For an existing workspace, use the
[incumbent adoption map](../threadlight-deploy/references/presenter-adoption.md);
do not regenerate the UI. Use
[`web_artifact_smoke.py`](../threadlight-deploy/scripts/web_artifact_smoke.py)
against final built files and the real server origin to catch omitted JSON/COPY
assets, incorrect `.mjs` MIME and non-root readability. These diagnostics do not
prove runtime identity: require the actual image, configured non-root user,
browser imports and promised download journey before hosted-quality claims.
See the [smoke evidence limits](../threadlight-deploy/references/web-artifact-smoke.md).
For an explicit [presenter-ready profile](../../docs/presenter-ready.md), design the
workspace **alongside the first end-to-end journey**, not after all backends.
Read the process-owned `specs/presenter-contract.json`: coherent fictional-company
identity, clear first action, editable inputs, evidence and useful outcome,
saved-result retrieval/reopen and understandable recovery. Keep technical
diagnostics secondary. Preserve the project's existing design system, framework
and chosen design tooling rather than replacing them with this reference.
Observe keyboard/focus, accessible labels/contrast, status beyond color, mobile
and desktop overflow with real text. Distinguish pending, failed, uncertain and
expired-source states; saved historical results retain their own authorized read
path after source/session expiry. Do not wire a reset-demo action that refreshes
data, resets consumed operations or clears uncertainty. Explicitly authorized
practice material is a new synthetic revision. Download/export panels are
conditional on the process promise, not mandatory for this profile.
Generate a curated, framework-agnostic **workspace UI** reference for a
designed threadlight process. The output is ONE polished example —
intentionally **shipped as pattern, not framework** — that the customer can
either drop into their preferred stack or rebuild faithfully.
> **Why framework-agnostic?** Customer constraint: web framework is
> irrelevant — the customer will rebuild in their stack (React, Angular,
> Vue, Blazor, native iOS, …). What matters is that the **shape** is
> right: the right filters, the right detail-pane sections, the right
> action toolbar, the right audit viewer placement. We ship that shape
> as one curated vanilla-JS+HTML reference plus a framework-mapping
> guide.
## When to Use
- After `threadlight-design` has produced `specs/SPEC.md` § 8b
- The process has a human operator who lives in this UI day-to-day
(not just an approval card in Teams)
- Examples: KYC analyst workspace, Order Fallout NOC console, Supplier
Risk control room, PIM enrichment editor
## When NOT to Use
- Process is fully autonomous (no human operator)
- Humans only interact via Teams approval card (use `threadlight-hitl-patterns` only)
- Customer provides their own UX (skip; just produce the action contract)
---
## Input contract / Output artifacts
**Input contract** — what this skill consumes:
- `specs/SPEC.md` § 8b **Human Interaction (Workspace UX)** — required
- `Workspace shape`: `case-list` | `inbox` | `dashboard` | `console` | `kanban` | `map`
- `Primary filters`
- `Detail pane sections`
- `Action toolbar` (subset of § 8 action gates)
- `Audit viewer` placement
- `Bulk operations`
- `specs/SPEC.md` § 4 **Data Models** — for entity field rendering
- `specs/SPEC.md` § 8 **Human Interaction Points** — action gate definitions
- `specs/sample-data/*.json` — to seed the demo with real-shaped data
- `AGENTS.md` — for the agent's name, identity, and skill catalog
- `specs/manifest.json` — for process name, traits, BR count
**Output artifacts** — what this skill produces:
```
src/workspace/
├── index.html # Single-file reference (vanilla HTML+CSS+JS)
├── workspace.css # Themed for the process
├── workspace.js # Filter / detail / action toolbar logic
├── seed-data.js # Loaded from specs/sample-data/ at build
├── README.md # How to rebuild in React/Angular/Vue/Blazor
└── components/ # Same components, broken out for copy-paste
├── case-list.html
├── detail-pane.html
├── action-toolbar.html
└── audit-viewer.html
```
The reference is **opinionated** — one polished implementation per workspace
shape — not a flexible framework.
> **Kratos-export mode.** A **Kratos-exported project** (`src/hosted-agent/` +
> `use-cases/<x>/`, trimmed `infra/` — see
> [`docs/KRATOS-BRIDGE.md`](../../docs/KRATOS-BRIDGE.md)) intentionally ships
> **without** a multi-tenant frontend module. This skill is the on-demand way to
> add an operator workspace on top of it. Output still lands under
> `src/workspace/`. Since the export has no `specs/SPEC.md` § 8b/§ 4, take the
> workspace shape, filters, and detail-pane sections **from the operator**, seed
> the demo from the export's `mocks/` directory (in place of
> `specs/sample-data/`), and read the agent identity from
> `use-cases/<x>/SYSTEM_PROMPT.md` + `agent.manifest.yaml`. Any agent skill the
> workspace references resolves at the skills root `use-cases/<x>/skills/`
> (override with `--skills-root`).
---
## Standard HITL panels (drop-in templates)
Three standard panels live in `references/hitl-panels/` — they're
**shape-agnostic** (drop into the right pane of `case-list`, `inbox`,
`kanban`; the center of `console`; or as a drawer triggered from
`dashboard` / `map`). Every workspace pilot needs all three; do not
ship a workspace without them.
| Panel | File | Purpose |
|-------|------|---------|
| **Decision pane** | `references/hitl-panels/decision-pane.html` | Agent recommendation + evidence + citations side-by-side |
| **Action toolbar** | `references/hitl-panels/action-toolbar.html` | BR-XXX-derived action gates (`approve / edit / reject / escalate`) with reason capture |
| **Audit viewer** | `references/hitl-panels/audit-viewer.html` | Read-only immutable audit log with CSV/PDF export |
**Shared data contract.** All three panels read from a single global
`window.threadlight` object (`activeCase`, `recommendation`,
`actions`, `audit`, `onAction`). Wire that object once from the seed
JSON or the agent's MCP server and all three panels light up.
See `references/hitl-panels/README.md` for the full contract +
"Drop-in instructions" + the demo stub. Vanilla HTML / CSS / JS — no
React, no build step; renders straight from `file://` for early
demos and stays clean inside an nginx ACA container for production.
**Why mandatory.** Recent pilots shipped without these panels and
got caught with a "workspace" that was a static file dump — no
analyst-facing decision surface, no action gates, no audit. The
remediation pass took ~30 min per panel using these templates. That
remediation is the last time we want to do this work; future pilots
copy these three files first, then style them per process accent.
## Workspace shapes (the catalog)
Each shape has its own polished reference. Pick one (driven by spec § 8b).
### `case-list`
The default for case-managed processes (KYC, claims, credit decisions).
**Anatomy:**
- **Top bar**: agent identity + global search + user avatar + reset-demo button
- **Left rail**: filter pills (status / owner / age / risk-band / SLA)
- **Center**: case-list (sortable columns; selection toggles right pane)
- **Right pane** (when case selected):
- Summary card (entity name, status badge, key fields)
- Agent reasoning trace (collapsed by default — "show why")
- Tool call log (collapsed — "show what the agent did")
- Action toolbar (gates from § 8)
- Audit viewer (drawer)
**Visual rules:**
- One accent color (per process)
- Status badges colorized by semantics (approved=green, declined=red,
pending=amber, escalated=violet)
- SLA countdown chip turns red at <10 min
- Agent reasoning rendered as numbered steps with tool icons
**Examples in catalog:**
- KYC analyst workspace (FSI)
- SMB credit memo review (FSI)
- Adverse media case review (FSI)
### `inbox`
For processes where items arrive continuously and operators work top-of-queue.
**Anatomy:**
- **Top bar**: same as `case-list`
- **Left**: chronological feed (newest top), grouping by hour/day
- **Right**: detail pane (same shape as `case-list` right pane)
- **Bulk action bar** appears when ≥1 item is multi-selected
**Visual rules:**
- Cards stack with subtle shadows
- Read state visually distinct (faded after view)
- "Mark all as read" / "Assign to me" bulk actions
**Examples:**
- Returns triage operator inbox (Retail)
- Insurance FNOL adjuster inbox (FSI)
### `dashboard`
For processes where operators monitor KPIs and drill into anomalies.
**Anatomy:**
- **Top bar**: same
- **KPI tiles row**: 4-6 large numeric tiles with sparklines
- **Anomaly feed**: list of "things needing attention" (links to case detail)
- **Drill-down modal**: opens for a tile or anomaly → shows underlying cases
**Visual rules:**
- KPI tiles use the BR-XXX → KPI mapping from spec § 9
- Sparklines reflect last 7 days (or process-appropriate window)
- Color rules: green (target met), amber (within ±20%), red (alert threshold breached)
**Examples:**
- Supplier Risk control room (Mfg)
- PIM catalog enrichment progress dashboard (Retail)
### `console`
For live operations — operator watches events stream in, takes action immediately.
**Anatomy:**
- **Top bar**: same
- **Split view**:
- Left: live event stream (newest top, auto-scroll with pause)
- Right: focused-event detail + action toolbar
- **Bottom rail**: connection status + active operators + reset-demo
**Visual rules:**
- New events fade in from the top
- "Pause auto-scroll" button when operator is reading
- Action toolbar always visible (no need to scroll)
**Examples:**
- Telco Order Fallout NOC console
- Network-fault triage dispatch console
### `kanban`
For case lifecycle visibility — items flow through ordered stages.
**Anatomy:**
- **Top bar**: same
- **Columns**: one per case stage (from spec § 4 state machine)
- **Cards**: one per case, drag-and-drop between columns (with audit gate)
- **Right drawer**: opens when card clicked, same detail-pane shape
**Visual rules:**
- WIP limits shown per column (subtle warning at 80%, hard at 100%)
- Cards colorized by age (green ≤4h, amber ≤24h, red >24h)
- Drag triggers an action gate (spec § 8 `edit-and-approve`) before commit
**Examples:**
- Order Fallout pipeline view (Telco — alternative to console)
- Loan origination pipeline (FSI)
### `map`
For geographically-distributed processes.
**Anatomy:**
- **Top bar**: same
- **Map area**: dot density / heatmap / region polygons
- **Filter rail**: same as case-list, plus region selector
- **Bottom drawer**: list of items in current viewport
- **Click on dot/region**: opens detail pane
**Visual rules:**
- Use a subtle base map (no full-color satellite)
- Dot color = severity/risk
- Cluster at low zoom, expand at high zoom
**Examples:**
- Supplier Risk world map (Mfg)
- Multi-region telco fault map (Telco)
### `chat`
For conversational agent processes where the primary interaction is natural
language Q&A — no case list, no operator dashboard, just a focused chat
experience backed by a Foundry hosted agent.
> **Added in May 2026** — the skill had 6 shapes
> but no conversational workspace. Chat-only agents are the majority of
> first-iteration PoCs; they were falling through the gap and getting
> built ad-hoc from scratch each time.
**Anatomy:**
- **Top bar**: agent identity (logo + name) + "New chat" button + mode badge ("Read-only PoC")
- **Left sidebar** (~260px):
- 3–5 starter prompt chips (from `tests/killer-prompts.md` K1–K3)
- Bonus prompts in a collapsible `<details>`
- Agent description / data source pills
- **Center**: chat transcript
- User messages (right-aligned, brand-tinted)
- Assistant messages (left-aligned, neutral card)
- Tool-call pills (animate in during streaming — `get_performance_summary` etc.)
- "Querying data sources…" placeholder while tools fire before text arrives
- Markdown rendering (marked.js CDN with local fallback)
- File download button when agent generates reports
- **Bottom**: auto-resizing textarea + send button
**Backend (FastAPI proxy — mandatory for ACA-hosted chat workspaces):**
The browser cannot hold an Entra token for `https://ai.azure.com/.default`
without a full MSAL app reg + CORS dance. A server-side proxy reuses the
UAMI already attached to the ACA container.
```python
# main.py — canonical pattern (battle-tested across multiple PoCs)
from azure.ai.projects.aio import AIProjectClient
from azure.identity.aio import DefaultAzureCredential
# Lifespan: create agent-bound OpenAI client
oai = project.get_openai_client(agent_name=AGENT_NAME)
# POST /api/invoke — non-streaming
response = await oai.responses.create(input=question, stream=False)
# POST /api/invoke-stream — SSE streaming
async for event in await oai.responses.create(input=question, stream=True):
if event.type == "response.output_text.delta":
yield f"data: {json.dumps({'type': 'text', 'chunk': event.delta})}\n\n"
elif event.type == "response.output_item.added":
yield f"data: {json.dumps({'type': 'tool', 'name': item.name})}\n\n"
# Keepalive every 8s to prevent ACA 504
```
**Required dependencies:**
```
fastapi>=0.115.0
uvicorn[standard]>=0.32.0
aiohttp>=3.10.0
python-multipart>=0.0.9 # Required for Form() — FastAPI won't parse form data without it
azure-identity>=1.19.0
azure-ai-projects>=2.1.0
openai>=1.55.0
markdown>=3.7
```
> **`python-multipart` gotcha (battle-scar).** FastAPI's `Form()` silently
> fails without `python-multipart` installed — returns 422 "Input should be a
> valid dictionary" instead of parsing form data. This broke the file export
> form POST for 3 debug cycles before we found it.
**Visual rules:**
- Same accent palette as the process (from `references/palettes.md`)
- Information-dense but calm — this is an everyday analyst tool, not a marketing page
- Tool pills use the same color as sidebar badges
- Auto-scroll to bottom on new messages
- `Cache-Control: no-cache` middleware on all static assets (demo-day cache bugs are devastating)
**Examples:**
- FMCG/CPG commercial sales advisor (single-agent conversational PoC archetype)
- Any first-iteration chat-only PoC
---
## Generation procedure
### Step 1: Read spec § 8b
```python
workspace_shape = spec["workspace_ux"]["shape"]
filters = spec["workspace_ux"]["primary_filters"]
detail_sections = spec["workspace_ux"]["detail_pane_sections"]
toolbar_gates = spec["workspace_ux"]["action_toolbar"] # subset of § 8 gates
audit_placement = spec["workspace_ux"]["audit_viewer"]
bulk_ops = spec["workspace_ux"]["bulk_operations"]
```
View on GitHub