Repository navigation
Conversation
Who OpenBot is for, what it must keep, and the brand inputs for the design work.
…ult skin New tokens live in app/src/openbot.css, scoped to :root:not([data-skin]), so OpenDuet, OpenDots and OpenMuse keep their look. theme.css is unchanged because the extension's pages import it. Inter stays for OpenDuet.
Eight palettes from the CopilotKit color family, picked by hashing the Bot's avatarSeed, so a rename never changes a Bot's color and no data is added.
Small idle orbs are drawn still, so a long sidebar does not animate dozens of blurred layers. Larger or working orbs use AgentOrb, toned so light palettes do not wash out to white.
AbstractAvatar and ChannelAvatar render BotOrb when no skin is set, so every avatar call site follows without changes. Skins keep their generated faces.
A conversation row says Waiting for you when an approval or question for its thread is pending, joined on the client from the approval inbox. Busy rows show the typing dots only. Times read 2m, 3h, 1d. The sidebar shares one gutter.
The placeholder cycles through one short line per Bot the person can reach, and holds while the composer has focus or text, or under reduced motion. The routing sentence shows only while there is a Bot to route to, as the old hint did.
The Bot's orb, name, role and visibility open the transcript and scroll away with it, without disturbing open-at-bottom, paging or the rail of turns. The inline approval reads as a card. The transcript rail still needs its own design pass.
…Audit Rows, cards and empty states get a firmer edge in the default skin. In Audit, Did not happen is a hollow mark instead of amber, so orange only ever means waiting for you.
Dark mode's --accent matched the menu surface, so the highlight in menus, pickers and comboboxes painted plum on plum. A lighter plum shows on both the menu and the page, and a test keeps the accent apart from both surfaces in light and dark.
A Bot's role can run to a paragraph, which filled half the conversation before the first message. The intro shows two lines and keeps the whole role on hover, on the Bot's page and in the detail pane.
samjulien
requested review from
MikeRyanDev,
davidmckayv,
dustywusty,
guidovizoso,
mxmzb and
tylerslaton
as code owners
October 30, 2026 15:14
- The composer column keeps its literal class, so OpenDuet's hook still finds it. openbot.css sets the default skin's centered 720px column. - The work row test looks for the Bot's orb, not an svg. - The OpenDots frame test sets the OpenDots skin, so its avatars are the OpenDots ones. - The pagination test answers the approval inbox, so it counts only channel requests.
Every grey token in the default theme moves to the matching slate step, in light and dark. The three greys that sat between palette steps keep their lightness and take slate's tint from the steps either side, so contrast does not shift. The onboarding illustration and the component preview's neutral-* classes become slate-* to match. Skins set their own colours and are unchanged.
The sidebar and the window's edge now share one tint, and the page sits in a panel inset 8px with rounded corners and a hairline, using the sidebar's own inset variant. Light mode runs darkest to lightest the way Linear does: the frame, a slate-50 panel, then white cards on it; dark mode was already in that order once the frame became its darkest surface. Admin and settings now scroll inside the panel like the app does, so its corners stay on screen; the audit table and the playground fill the panel instead of the window. Fields fill with the card's white so they read as fields on a card or the panel, and row icon tiles take the panel's grey with a hairline so they still show on a white card.
The conversation's main line was 14.4px, sized by hand; it is now text-sm like the rest of the sidebar. The tests that named the old size class follow.
Page titles are semibold with slightly tighter tracking instead of bold. Section titles drop from 18px bold to 15px semibold, close to body size, so a long page reads as one title and its parts rather than a row of titles competing with each other.
Plugins showed one plug icon on every row, so the icons told one vendor from another no better than none. Rows now show the app's logo, its brand icon, or its initial; Connections and the app directory fall back to the initial too. The More apps row, a directory rather than a vendor, gets an apps icon. In the admin sidebar Skills and Automatic learning shared a file icon; they are now a slash and a bulb.
The small uppercase OPENBOT over "Start a conversation" repeated what the sidebar already says and gave the page two headings where one does the job. The greeting is now the page's only title, in the same semibold as other page titles.
The carousel's tall cards left about 50px of nothing between each avatar and its name, and its arrows showed even when every card fit. Bots are now rows (avatar beside name and one line of what the Bot is for) two to a line, up to four, with an All Bots link when there are more. The skeleton, empty and error states reserve the same two rows so the composer does not move.
"Review this Bot's activity and settings." could head any page. The description under the title is now the Bot's own one-liner, which used to sit just below in the avatar block; that block keeps the avatar and the Bot's title.
With nothing running or scheduled, Activity was a whole section holding one row, "All activity · Nothing yet". That row now sits at the end of For you, titled Activity. The section still shows, with its rows to running and scheduled work, whenever there is any.
…button
GitHub's tile line was a full sentence cut off mid-word; tiles now carry a short version that fits
("Repository events can start Bots."), and the full sentence stays on GitHub's own page. An app
with no summary of its own no longer shows "Connect your Todoist account.", which only repeated
the Connect button beside it; the tile shows just its name.
… its count
The full directory takes a couple of seconds to arrive, and until then the page was a search box
over blank space. It now shows placeholder rows while loading, then how many apps there are
("1,605 apps. Search by name to narrow them.") or how many match a search.
Sam's square-dot matrix (from the design-uplift branch) now sits faintly behind every PageEmpty, fading out from the top-right corner. It is built to be changed without touching a component: - the tile is app/src/assets/patterns/dot-matrix.svg, used as a mask, so replacing the file changes the pattern; - --empty-pattern, --empty-pattern-color and --empty-pattern-opacity in theme.css point at the file and set its colour and strength, per theme; - --empty-pattern-opacity: 0 turns it off. Skins start with it off, since it is drawn for OpenBot's own palette.
The sidebar draws Bots as a lightning bolt, but empty states about Bots (no Bots yet, no other Bots to hand off to, Bot not found) drew a robot. They now use the same bolt, so the two read as one thing.
Conflicts: - page-parts.tsx: PageEmpty takes Guido's empty-state pattern. - Home: Guido's layout and Bot cards. The default skin keeps its subheader above the composer and the rotating examples. The composer keeps its stock frame.
The default look's colors move into theme.css as plain shadcn tokens, on Guido's hierarchy: the sidebar frame darkest, the off-white panel, then white cards. The grays lean towards CopilotKit's lilac, the ring is its periwinkle, and dark mode keeps the plum ground. openbot.css keeps only the default skin's typeface and the orb's edge and tone. The extension's notice copies the new tokens, and the token test pins the three surfaces in both themes.
- Rows, cards and empty states use Guido's page parts: no custom edge, shadow or wash. - The sidebar uses Guido's inset frame, and its rows keep the stock padding. - The approval card keeps its orange tint, the color for "waits for you", in the stock card shape. - The composer loses the height prop that only Home's old frame used.
The dots behind a Bot's orb read Guido's --empty-pattern tokens, so swapping or turning off the pattern changes both places, and skins start without it.
This reverts commit 7125aac.
This reverts commit d412533.
This reverts commit 6028a21.
Guido's inset frame, three surfaces, shadcn components and empty-state pattern stay. What comes back is the uplift's look, which the merge had dropped: - The palette's exact values, the lilac selected row and the 0.625rem radius. The frame is CopilotKit's pale lavender in light and the plum #1f1c2c in dark. - The firmer edge and soft lift on rows, cards and Home's Bot cards, and the faint wash and edge on empty states, behind the pattern. - Home's composer frame and the 32px bold greeting, on Guido's centered layout. - The orange approval card, the sidebar's shared left edge, and the composer height prop. - Home's Explore Bots error and empty states, which the heading revert's conflict had dropped. The extension's notice copies the restored tokens and radius.
So a customer restyles the default look from theme.css alone: - Card edge and lift are --card-border, --card-shadow and --card-shadow-hover, registered as border-card-border, shadow-card and shadow-card-hover. Page rows, cards, empty states and Home's Bot cards use them. skins.css sets them back to each skin's plain hairline, as it does for the empty-state pattern. - Orange is --warning and --warning-foreground, used by the approval card and "Waiting for you". - Home's composer uses a raised variant on the composer instead of styling its form from outside. - The transcript's centered column is set in openbot.css through a transcript-column slot, as the composer's already was. - The approval card, tool-line cards, the audit's hollow "Did not happen" mark and the sidebar's gutters no longer check the skin. Two fixes for Guido's surface order: empty states lose their wash, which sat darker than the page, and dark secondary and muted fills are now lighter than cards rather than the frame's color.
The move to theme tokens had also changed OpenDuet, OpenDots and OpenMuse. Each is back to what it drew before: - The approval card, tool lines, the audit's "Did not happen" mark and the sidebar's gutters keep their skin check. OpenBot's own versions still take orange from the --warning tokens. - Home's raised composer and bolder greeting are OpenBot's own; a skin keeps the default composer. - Empty states take their edge from a new --empty-border token, so a skin keeps its hairline in dark mode, where rows and cards have none.
The transcript column's data-slot replaced the scroller content's own, which the paging tests and the scroller look for. The column is marked with data-transcript-column instead.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A design uplift for OpenBot's default look, combined with Guido's inset panel from #912. It changes how the app looks, not what it does.
From #912 (merged in, Guido's commits kept as they are):
The uplift's look on top:
How the look is built
theme.css, as plain shadcn tokens. A customer restyles the default look from that one file.--warningand--warning-foregroundfor orange.--card-border,--card-shadowand--card-shadow-hoverfor the card edge and lift, registered asborder-card-border,shadow-cardandshadow-card-hover.--empty-borderfor the edge of empty states.raisedvariant, which Home uses.openbot.csskeeps only what is not a color: the typeface, the orb's edge and tone, and the conversation's centered column.What stays the same
skins.cssresets the card and empty-state tokens for them, as it already does for the empty-state pattern.theme.csstokens, and a test keeps the copy in step.Changed from #912
These are reverted on purpose. Each revert is its own commit, so it is easy to discuss or drop:
New client-side behavior
threadId. Approvals and questions both carry it.2m,3h,1d. This uses a newrelativeTimeShort(), so the other screens keep their longer format.Testing
Only the touched tests were run, plus typecheck, lint and the build:
main.approvals-rules.test.tsx. Each times out at about one second on a local machine. CI is the check for these.Follow-up
Screenshots
Taken from a local OpenBot with real data, at 1440×900.
Home: before and after
Light and dark