The assistant carried its own bar above the layout, on top of the blue app
header that both pages now share. On desktop it held a visually-hidden title, a
mobile-only drawer button and a status pill — so it was mostly dead space, and it
made the assistant taller than the app page it is supposed to match.
The bar is gone. The ready/busy indicator moved into the composer footer, next to
the work it describes, and the drawer button floats on phones rather than
occupying a strip the desktop layout does not have. The rail now sticks to the
top of the layout instead of 52px below a bar that no longer exists.
The menu toggle used fa-table-columns, a split-pane glyph that does not read as
"menu". Both copies now use fa-bars and rotate when collapsed to show which way
they will act.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GmpYHPSLGmXGZMyLpn2Lbe
Sources (correcting what I built earlier)
The previous toggle branched the SYSTEM PROMPT, so the same question could get a
different answer depending on a display setting — the bias this was meant to
avoid. The prompt is now unconditional: buildSystemPrompt takes no display
argument and is byte-identical either way. Hiding sources happens on the way out
— the server omits them and strips the now-orphaned [n] markers from the copy it
sends. The answer is generated, stored and exported with citations intact, so
turning the setting back on restores them without re-asking anything. Renamed to
clinical_assistant.show_sources; the old key is still honoured.
Signed-out preview (admin opt-in, default off)
A visitor may try the assistant; reaching for the workspace asks them to sign in.
Deliberately narrow:
- Reachable paths are an exact allow-list, not a pattern, so a new endpoint is
private unless someone adds it on purpose.
- A preview visitor gets no identity at all (id: null), so nothing can be owned,
saved, billed or addressed to them.
- The image tool is withheld rather than left to fail on a null owner, and no
audit rows are written.
- A caller presenting a token is authenticated normally, so preview can never
downgrade a real session; if the setting cannot be read, authentication is
required.
- Actions needing an account are hidden rather than offered and refused.
Composer
The bar above the transcript is gone. Patient take home, Export PDF, Download
transcript and Attach images moved into a + menu in the composer, and the model
selector moved beside send — shown only when there is more than one model, as
before. Both views now start at the same top edge, so switching modes cannot
nudge the page up or down. On an empty transcript the tiled ground runs behind
and below the composer, which floats on it above centre.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GmpYHPSLGmXGZMyLpn2Lbe
Three faults from moving the switch into the app sidebar:
1. Clicking Assistant did nothing. activateTab() bailed unless a matching
.tab-btn existed, and removing the "AI Assistant" nav entry removed exactly
that — so every /assistant visit fell through to the fallback tab. A tab
reached from the mode switch legitimately has a section without a button, so
activateTab now keys off the section and only touches the button if present.
2. The switch overflowed its box. The sidebar is 210px; without min-width:0 the
two buttons refused to shrink below their content. They now shrink, with a
slightly tighter font and gap so both labels fit.
3. "Hide menu" had no way back. The toggle sits inside the sidebar it collapses,
so it disappeared with it. It now leaves the collapsing box and pins itself
beside the content, in both the app sidebar and the assistant rail, and the
label already flips to "Show menu".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WjVc5oaAaYFNbZGLeJp6TX
The Assistant/Workspace switch and the menu toggle rendered as unstyled native
buttons in the app sidebar. Their CSS was in assistant.css, which is pulled in by
the assistant COMPONENT — so it is simply absent on "/", where those controls now
also render.
Both moved to styles.css, which every page loads. A stale duplicate of the switch
rules was also still sitting in assistant.css; that is exactly how two copies
drift and one silently wins, so it is gone.
Adds a test that walks the classes rendered in index.html and asserts each is
defined in styles.css and NOT duplicated in assistant.css, which would have
caught this before it shipped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WjVc5oaAaYFNbZGLeJp6TX
The app IS workspace mode, so the switch belongs in both places and the only
difference between the two screens is which pill is highlighted:
- The app sidebar's "AI Assistant" nav entry is replaced by the switch, with
Workspace highlighted. The assistant rail carries the same control with
Assistant highlighted. Clicking Assistant from the app navigates to
/assistant; inside the assistant, Workspace opens the launcher in place.
- Accent corrected: I had it backwards last round and turned the assistant
purple. The app's accent is blue (.tab-btn.active in styles.css); the
assistant now uses it throughout, so neither screen looks like a different
product. Citation chips keep purple so evidence stays distinct from
interactive blue.
- One menu toggle labelled "Hide menu", shared by the app sidebar and the
assistant rail. It replaces three separate controls: a pin button, a floating
expand button, and the assistant's own rail toggle. The toggle stays reachable
when the rail it collapses is hidden, or there would be no way back.
- Workspace cards list clinical work only. Settings, FAQ, Admin, Docs and
Content Manager stay in the app sidebar under Account, where they belong.
- Model availability is discovery-only again: a hand-typed id cannot be verified
at that point, so the manual entry field is gone.
The in-page mode state machine is removed along with the whole class of
hidden-versus-display bugs it carried.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WjVc5oaAaYFNbZGLeJp6TX
The mode switch was toggling the `hidden` attribute on elements that each carry
their own `display:` rule. A class selector beats the UA stylesheet's
[hidden]{display:none}, so every one of those toggles silently did nothing —
which is why workspace mode still showed the chat, and why coming back never
restored the saved-chat list. Every affected element was in that state.
CSS now owns both modes from a single body class, in one block, and the JS does
nothing but set that class. No element.hidden juggling remains.
One accent. The assistant used --blue for user bubbles, focus rings, blockquotes
and example pills while citations, cards and the mode switch used --purple, so
the two halves read as two different apps. Purple was already dominant (23 uses
to 6) and is the assistant's identity, so blue is gone entirely. Source cards
pick up the same shape, shadow and hover accent as the workspace cards, and a
targeted citation highlights in the accent instead of a bare border.
Go back is removed from both the topbar and the rail: the Assistant/Workspace
switch is how you leave now, and the dead handler went with it.
Create image no longer takes a full-width gradient row competing with New chat;
it is a square icon button beside it with a tooltip and an aria-label.
Also guards the delegated document listeners against double registration.
initIfNeeded already prevented a second bind in production, but nothing stopped
a stray bindEvents() from double-firing every click — which is exactly what the
test harness hit, activating a tab twice from one click.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WjVc5oaAaYFNbZGLeJp6TX
Both surfaces render from the same pass over the app's real .tab-btn list, so
neither can drift from the menu it mirrors.
- The card view now shares the empty state's graph-paper ground, card language
and spacing, and is centred with a max width, so switching modes reads as the
same app instead of a page that looks nothing like it.
- Cards carry the clinical work tabs only: Settings, Admin, Docs and FAQ stay in
the rail list, where someone looking for them will go, rather than sitting
alongside Encounter HPI and Calculators.
- On phones the card grid is hidden entirely and the chat stays on screen — the
drawer already is the menu there, so a second copy only pushed it away.
- The Sources column and its 330px grid track both go in workspace mode.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkfrkQwA4YGrGw9LZSpeAq
Workspace mode rendered the app menu twice — once in the rail and again as a
card grid that replaced the chat column — so clicking it landed you somewhere
that looked nothing like the assistant. There is one menu now: the rail swaps,
the chat column stays where it is.
The Sources panel was already hidden in workspace mode, but its 330px grid track
was not, leaving an empty gutter. Both collapse states now drop the track.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkfrkQwA4YGrGw9LZSpeAq
The rail's Workspace section was a collapsible extra sitting under the chats.
It is now the second of two modes, selected by a segmented switch at the top of
the rail:
- Assistant keeps the chat column, the saved-chat list, New chat and Create image.
- Workspace REPLACES the chat column and the Sources panel with the app's own
menu — a card grid in the main column and the same list in the rail — so
nothing from the assistant is left half-visible beside it.
Both the rail list and the cards are built from the app's real .tab-btn
elements, so a tab added, renamed or hidden in index.html follows automatically.
Learning Hub moved down from second place to sit immediately before Content
Manager, with the other content tools rather than above the clinical ones.
Also removed dead CSS for .assistant-view-switch, .assistant-learning-view and
#assistant-learning-root: that markup no longer exists anywhere in the app.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkfrkQwA4YGrGw9LZSpeAq
Mobile
body.assistant-workspace .assistant-layout is both later in the file and more
specific than the .assistant-layout rule inside @media (max-width:640px), so
phones were inheriting height: calc(100vh - 64px) — an offset for the app header
that workspace mode already hides — plus grid rules on a flex container. The
topbar then overlapped the content. Added a matching-specificity mobile override
restoring 100dvh and the flex layout.
Workspace menu in the rail
The saved-chats rail gains a collapsible Workspace section listing the app's own
tabs, so the assistant sidebar carries both its chats and the workspace
navigation. It is built from the real .tab-btn elements rather than a second copy
of the menu, so tabs added, renamed or hidden in index.html follow automatically
and admin-only tabs stay hidden.
Prompt
Rewritten as principles instead of an enumerated rulebook: "respond to the user's
latest message, not to an earlier one", "if it carries no question, ask what they
would like you to look up", "never repeat a previous answer", and for the tool
"use it when the latest message asks for a picture, or for a change to one you
just made, and not otherwise". No example words in any language remain — the
model reads the message as written. 1032 -> 788 characters.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkfrkQwA4YGrGw9LZSpeAq
.assistant-layout.history-collapsed set display:none on .assistant-history, which
removes it from grid flow. The layout still declared three tracks
(0 / minmax(0,1fr) / 330px), so the two remaining items shifted left: .assistant-main
took the 0 track and #assistant-sources took the 1fr. Collapsing the sidebar made
the chat vanish and rendered the citations in its place. The rail is now a
zero-width, visibility:hidden grid item, so the columns stay where they belong.
Also: inside the assistant workspace the topbar no longer repeats "AI Clinical
Assistant" — the page is the assistant. It stays in the DOM, visually hidden, so
screen readers still announce it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkfrkQwA4YGrGw9LZSpeAq
Saved chats
Grouped the way Open WebUI groups them: Pinned, Today, Yesterday, Previous 3
days, Previous 7 days, Previous 30 days, then calendar months (with the year
once it is not the current one). Chats with no usable timestamp land in Undated
rather than disappearing.
Sidebar toggle
The collapse button used <i class="fas fa-sidebar">, which is a Font Awesome PRO
icon; on the Free 6.5.0 build this app loads it rendered nothing, so the toggle
has been an invisible button since it shipped. It now uses fa-table-columns,
keeps aria-expanded/aria-controls in sync, flips its label between "Hide saved
chats" and "Show saved chats" so the collapsed state is escapable, and animates.
Acknowledgements
"Окей", "Nice", "Perfect", "gracias" and friends now get the existing
"What clinical question would you like me to look up?" reply instead of a
retrieval and a paid generation. "yes", "sure", "no" and "more" are deliberately
excluded: answers end by offering more detail, so those must still be answered.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkfrkQwA4YGrGw9LZSpeAq