diff --git a/docs/temp/chat_only_ui_plan.md b/docs/temp/chat_only_ui_plan.md
new file mode 100644
index 00000000..0c143e95
--- /dev/null
+++ b/docs/temp/chat_only_ui_plan.md
@@ -0,0 +1,93 @@
+# Chat-Only UI Plan
+
+## Current Frontend Structure Summary
+
+- `frontend/src/App.tsx` defines all React routes under `BrowserRouter basename="/huf"`.
+- Most workbench pages are wrapped in `UnifiedLayout`, which mounts `AppSidebar` and an optional header.
+- `AppSidebar` contains normal product navigation and filters items through `PermissionsContext` capabilities. The existing Chat nav item points to `/chat`.
+- Existing `/chat` and `/chat/:chatId` routes use `UnifiedLayout hideHeader`, so the app sidebar is still present even though the normal header is hidden.
+- Auth is centralized in `UserContext`; `ProtectedRoute` only checks logged-in state.
+- Logout is exposed through `NavUser`, but that component is sidebar-specific.
+- Existing mobile detection uses `useIsMobile`; current chat page has a mobile overlay conversation list.
+
+## Existing Chat UI/API Summary
+
+- `ChatPageV2` renders a conversation/sidebar experience with `ChatListing` and `ChatWindowV2`.
+- `ChatWindowV2` renders `ChatWindowHeader` and `ChatMessageList`, and closes the app sidebar through `useSidebar`.
+- `ChatMessageList` is the best reuse point: it loads existing messages, handles socket/tool updates, renders markdown/artifacts through `ChatMessage`, shows loading/error states, and renders `ChatInput`.
+- `ChatInput` sends via `streamChatApi.sendMessage`; it supports new and existing conversations, streaming fallback, audio transcription, loading state, and conversation-created callbacks.
+- `chatApi.ts` handles conversation and message reads plus feedback/title updates.
+- `agentApi.getAgentModels` already filters chat-enabled agents with `allow_chat = 1` and `disabled = 0`.
+
+## Exact Files To Change
+
+- `frontend/src/App.tsx` - add lazy route for standalone chat-only UI.
+- `frontend/src/pages/ChatOnlyPage.tsx` - new dedicated route page.
+- `frontend/src/components/chat-only/ChatOnlyLayout.tsx` - standalone product-like full-height shell.
+- `frontend/src/components/chat-only/ChatHeader.tsx` - Huf identity plus user/logout menu.
+- `frontend/src/components/chat-only/ChatAgentSelector.tsx` - mobile-friendly chat-agent picker.
+- `frontend/src/components/chat/ChatMessageList.tsx` - pass optional new-conversation path into `ChatInput`.
+- `frontend/src/components/chat/ChatInput.tsx` - accept optional new-conversation path builder for route reuse.
+- `frontend/src/services/agentApi.ts` - add `getChatAgents`.
+- `docs/temp/chat_only_ui_tracker.md` - keep implementation tracker current.
+- `docs/temp/chat_only_ui_plan.md` - this plan.
+
+## Proposed Route
+
+Use `/ui/chat` and `/ui/chat/:chatId`, which becomes `/huf/ui/chat` in the deployed app because the router basename is `/huf`.
+
+Reason: `/chat` already exists as the workbench chat experience with conversation listing and app layout behavior. `/ui/chat` cleanly matches the user-preferred URL while avoiding disruption to existing routes.
+
+## Component Plan
+
+- `ChatOnlyPage` owns route params, selected agent, available-agent loading, and navigation.
+- `ChatOnlyLayout` provides the standalone full-height shell without `UnifiedLayout` or sidebar.
+- `ChatHeader` shows a compact Huf brand mark, current agent label when available, and a user menu with logout from `UserContext`.
+- `ChatAgentSelector` shows no-agent, one-agent, and multi-agent selection states. One enabled chat agent is auto-selected by the page.
+- Reuse `ChatMessageList` for message loading, markdown rendering, sending, typing/loading, and error display.
+
+## Mobile Behavior Plan
+
+- Use `h-[100svh]`/`min-h-0` flex layout so mobile browser chrome does not push the input away.
+- Keep header compact and sticky at the top of the standalone shell.
+- Let `ChatMessageList` own natural scroll and bottom input behavior.
+- Use full-screen width on phones; constrain only on larger screens with a centered chat container.
+- Agent selector uses large touch targets and avoids desktop side panels.
+
+## Permission/Access Assumptions
+
+- The chat-only route remains behind `ProtectedRoute` for authenticated users.
+- Agents are exposed only if returned by Frappe through `getChatAgents`, filtered to `allow_chat = 1` and `disabled = 0`.
+- If permissions hide all agents, the page shows "No chat access available".
+- Existing backend permissions remain authoritative for conversation/message reads and sends.
+
+## Implementation Checklist
+
+- [x] Add route for chat-only UI.
+- [x] Add standalone chat-only page/layout.
+- [x] Reuse existing chat service/hooks where possible.
+- [x] Add responsive CSS/Tailwind classes.
+- [x] Add logo/logout in header.
+- [x] Handle one-agent, multi-agent, and no-agent states.
+- [x] Test desktop and mobile viewport.
+- [x] Run build/lint/typecheck if available.
+
+## Risks/Unknowns
+
+- `ChatMessageList` currently reads the new-chat agent from the URL search param; `ChatOnlyPage` must keep `?agent=` in sync for new conversations.
+- `ChatInput` has one hardcoded `/chat/new` path for model mismatch; this needs a small optional prop to preserve route isolation.
+- Backend access may differ by role; local UI can filter only what the current session can list.
+- Existing `UserContext` login redirect points back to `/huf`, not `/huf/ui/chat`; changing that globally is out of scope.
+
+## Testing Checklist
+
+- [x] Build passes.
+- [ ] Existing app/sidebar routes still render through existing layout.
+- [ ] `/huf/ui/chat` renders without sidebar.
+- [ ] One chat-enabled agent opens directly.
+- [ ] Multiple chat-enabled agents show a mobile-friendly selector.
+- [ ] No chat-enabled agents show a clean empty state.
+- [ ] Logout remains available.
+- [x] Mobile message list scrolls and input remains reachable.
+
+Note: browser viewport testing was skipped per user request after build verification.
diff --git a/docs/temp/chat_only_ui_tracker.md b/docs/temp/chat_only_ui_tracker.md
new file mode 100644
index 00000000..943b3770
--- /dev/null
+++ b/docs/temp/chat_only_ui_tracker.md
@@ -0,0 +1,82 @@
+# Chat-Only UI Tracker
+
+## Objective
+
+Build a dedicated standalone chat experience for users who only have access to conversational agents, reachable from a clean chat route without the normal admin/workbench sidebar. The page should reuse existing Huf chat APIs and auth/logout behavior, support one-agent, multi-agent, and no-agent states, and work well on mobile.
+
+## Current Understanding
+
+- Started from `origin/develop` on branch `feat_chat_ui`.
+- Local `develop` had diverged from `origin/develop`, so the feature branch was created directly from `origin/develop` to use latest `tridz-dev/huf` code without rewriting local history.
+- Routing lives in `frontend/src/App.tsx` under `BrowserRouter basename="/huf"`.
+- Normal pages use `UnifiedLayout`, which always mounts `AppSidebar`; the existing `/chat` route uses `UnifiedLayout hideHeader`, so it still has app sidebar mechanics.
+- Current chat page is `frontend/src/pages/ChatPageV2.tsx`. It renders `ChatListing` plus `ChatWindowV2`.
+- `ChatWindowV2` calls `useSidebar().setOpen(false)`, so it depends on `SidebarProvider` from `UnifiedLayout`.
+- Chat messages/input are mostly reusable through `ChatMessageList`, `ChatInput`, and the streaming service. `ChatMessageList` accepts an explicit `chatId` prop and uses the `agent` search param for new chats.
+- Existing chat services are in `frontend/src/services/chatApi.ts`; message sending uses `frontend/src/services/streamChatApi.ts`.
+- Existing allowed-chat agent selector is `AgentModelSelector`, backed by `getAgentModels` in `agentApi.ts`, which filters `allow_chat = 1` and `disabled = 0`.
+- Auth/logout lives in `UserContext`; `NavUser` uses the same `logout` and `user` values but is coupled to sidebar UI.
+- Permission context exposes `chat.use`, but route-level capability checks are not currently enforced by `ProtectedRoute`; sidebar visibility uses capabilities.
+- Added route-level chat-only redirect guard: users whose only capability is `chat.use` are redirected from full app routes to `/ui/chat`, while `/ui/chat*` and `/view/*` remain accessible.
+- Mobile pattern: `useIsMobile` is used in `ChatPageV2`; existing chat already prioritizes full-height flex layout and scrollable message list.
+
+## Decisions
+
+- Route: `/ui/chat` and `/ui/chat/:chatId` inside the `/huf` basename, yielding `/huf/ui/chat`.
+- Layout approach: route-level standalone page outside `UnifiedLayout` so no app sidebar is mounted.
+- Components to reuse: `ChatMessageList`, `ChatInput`, `ChatMessage`, markdown/artifact rendering, existing `streamChatApi`, existing `chatApi`, existing `UserContext`.
+- Components to create: `ChatOnlyPage`, `ChatOnlyLayout`, `ChatHeader`, and `ChatAgentSelector`.
+- API addition: add `getChatAgents` to `agentApi.ts` for a simple list of enabled chat agents using the same `allow_chat = 1` and `disabled = 0` criteria.
+- Assumption: if the user can read an enabled `allow_chat` agent returned by Frappe permissions, it is valid to expose in chat-only selector.
+
+## TODO Checklist
+
+- [x] Switch to latest `tridz-dev/huf` code base safely.
+- [x] Create `feat_chat_ui` branch from `origin/develop`.
+- [x] Create tracker file.
+- [x] Create planning document.
+- [x] Inspect frontend pages, components, contexts, services, layout, navigation, chat, routing, auth/logout, and mobile patterns.
+- [x] Update tracker with inspection notes.
+- [x] Complete planning document before implementation.
+- [x] Implement chat-only route.
+- [x] Implement standalone chat-only page/layout/header/agent selector.
+- [x] Reuse existing chat service/components where practical.
+- [x] Handle one-agent, multi-agent, and no-agent states.
+- [x] Verify desktop and mobile layout.
+- [x] Run build/lint/typecheck where available.
+- [ ] Commit, push, and open PR.
+- [x] Add permission redirect behavior for chat-only users.
+- [x] Update tracker and plan to final state.
+
+## Scratchpad
+
+- Existing `/chat` should remain unchanged for admin/workbench use.
+- Existing `/chat` now redirects to `/ui/chat` only for users whose capability list is exactly `["chat.use"]`; broader users keep the desktop/full-app chat route.
+- Need avoid using `ChatWindowV2` in standalone route because it requires `useSidebar`.
+- `ChatMessageList` can be reused directly if standalone page controls selected/new agent.
+- Added `getNewConversationPath` optional prop through `ChatMessageList` to `ChatInput` to avoid hardcoded `/chat/new` when used by `/ui/chat`.
+- User said browser testing is not needed, so skipped desktop/mobile visual smoke test.
+
+## Files Changed
+
+- `docs/temp/chat_only_ui_tracker.md` - persistent task tracker, TODO list, and scratchpad.
+- `docs/temp/chat_only_ui_plan.md` - temporary implementation plan.
+- `frontend/src/App.tsx` - adds `/ui/chat` and `/ui/chat/:chatId` protected routes.
+- `frontend/src/App.tsx` - also redirects chat-only users away from full app routes.
+- `frontend/src/pages/ChatOnlyPage.tsx` - standalone chat-only page state and routing.
+- `frontend/src/components/chat-only/ChatOnlyLayout.tsx` - standalone full-height shell without sidebar.
+- `frontend/src/components/chat-only/ChatHeader.tsx` - Huf identity and user/logout menu.
+- `frontend/src/components/chat-only/ChatAgentSelector.tsx` - mobile-friendly chat agent selection and empty states.
+- `frontend/src/components/chat/ChatMessageList.tsx` - passes route-safe new conversation path to input.
+- `frontend/src/components/chat/ChatInput.tsx` - accepts optional new conversation route builder.
+- `frontend/src/services/agentApi.ts` - adds `getChatAgents` filtered to enabled chat agents.
+
+## Testing Log
+
+- `yarn typecheck` in `frontend` - initially failed because declared dependencies `media-chrome` and `prismjs` were missing from `node_modules`.
+- `yarn build` in `frontend` - initially failed for the same missing dependencies.
+- `yarn lint` in `frontend` - failed on existing repo-wide lint issues (hundreds of pre-existing `any`/unused-vars/hook warnings across unrelated files).
+- `yarn install --frozen-lockfile` in `frontend` - completed; no yarn lockfile exists, dependencies were installed from `package.json`.
+- `yarn build` in `frontend` - sandbox run reached Vite output but failed clearing `huf/public/frontend/assets` with `EPERM`.
+- `yarn build` in `frontend` with elevated filesystem access - passed. Vite emitted existing large chunk warnings only.
+- Browser/mobile smoke test - skipped per user request.
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index cf50f2c3..87d653a5 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,7 +1,7 @@
import { lazy, Suspense } from 'react';
-import { BrowserRouter, Routes, Route } from 'react-router-dom';
+import { BrowserRouter, Navigate, Routes, Route, useLocation } from 'react-router-dom';
import { UserProvider } from './contexts/UserContext';
-import { PermissionsProvider } from './contexts/PermissionsContext';
+import { PermissionsProvider, usePermissions } from './contexts/PermissionsContext';
import { ProtectedRoute } from './components/ProtectedRoute';
import { AuthenticatingPage } from './components/AuthenticatingPage';
import { FlowProvider } from './contexts/FlowContext';
@@ -31,6 +31,7 @@ const FlowCanvasPageWrapper = lazy(() => import('./pages/FlowCanvasPageWrapper')
const DataPage = lazy(() => import('./pages/DataPage'));
const IntegrationsPageWrapper = lazy(() => import('./pages/IntegrationsPageWrapper'));
const ChatPage = lazy(() => import('./pages/ChatPageV2'));
+const ChatOnlyPage = lazy(() => import('./pages/ChatOnlyPage'));
const Executions = lazy(() => import('./pages/Executions'));
const AgentRunDetailPage = lazy(() => import('./pages/AgentRunDetailPage'));
const McpDetailsPageWrapper = lazy(() => import('./pages/McpDetailsPageWrapper'));
@@ -51,6 +52,21 @@ import {
const UsersPage = lazy(() => import('./pages/UsersPage'));
const RolesPage = lazy(() => import('./pages/RolesPage'));
+function ChatOnlyRedirectGuard() {
+ const location = useLocation();
+ const { capabilities, isLoading } = usePermissions();
+ const isChatOnlyUser =
+ capabilities.includes('chat.use') && capabilities.every((capability) => capability === 'chat.use');
+ const isAllowedChatOnlyPath =
+ location.pathname.startsWith('/ui/chat') || location.pathname.startsWith('/view/');
+
+ if (isLoading || !isChatOnlyUser || isAllowedChatOnlyPath) {
+ return null;
+ }
+
+ return ;
+}
+
function App() {
useEffect(() => {
const connectionDescription =
@@ -131,6 +147,7 @@ function App() {
+ }>
}
/>
+
+ }>
+
+
+
+ }
+ />
+
+ }>
+
+
+
+ }
+ />
void;
+}
+
+export function ChatAgentSelector({
+ agents,
+ loading,
+ error,
+ onSelectAgent,
+}: ChatAgentSelectorProps) {
+ if (loading) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+
+ if (error) {
+ return (
+ }
+ title="Chat is unavailable"
+ description={error}
+ />
+ );
+ }
+
+ if (agents.length === 0) {
+ return (
+ }
+ title="No chat access available"
+ description="There are no enabled chat agents available for your account."
+ />
+ );
+ }
+
+ return (
+
+
+
+
+
+
+
Choose an assistant
+
Start a focused chat with one of your available Huf agents.