Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
be9605e
feat(theme): follow the system's dark mode, with an Appearance setting
jerelvelarde Oct 28, 2026
ef40675
feat(ui): a visual system of cool greys, one accent and five type sizes
jerelvelarde Oct 28, 2026
635bf8a
feat(orb): an orb drawn on a canvas, in a colour for each Bot
jerelvelarde Oct 28, 2026
28d2b5f
feat(orb): one animation clock for every orb, and eyes that follow th…
jerelvelarde Oct 28, 2026
f20d0fb
feat(orb): every Bot and OpenBot's own mark draw the orb
jerelvelarde Oct 28, 2026
9130e04
feat(orb): conversation faces and onboarding's example Bots draw the orb
jerelvelarde Oct 28, 2026
8eace8c
docs: changelog for OpenBot's new look
jerelvelarde Oct 28, 2026
c56d122
fix(orb): keep small faces in their circles, sharp on any screen, sti…
jerelvelarde Oct 28, 2026
d32d624
fix(orb): the skins draw the orb too
jerelvelarde Oct 28, 2026
ca7f7dc
fix(orb): OpenMuse's header draws its face at the size of its slot
jerelvelarde Oct 29, 2026
8bad1bd
fix(orb): a face at rest draws nothing until it changes
jerelvelarde Oct 29, 2026
8685483
fix(orb): two Bots in one colour no longer share a face, and none is …
jerelvelarde Oct 29, 2026
bc44ee9
fix(orb): every colour reads as its own at list size, and the shipped…
jerelvelarde Oct 31, 2026
d2d6cd7
fix(theme): focus rings this look draws clear 3:1 in both themes
jerelvelarde Oct 31, 2026
114a992
fix(orb): faces in a list are still at rest, and a person can still t…
jerelvelarde Oct 31, 2026
7f551e5
feat(settings): Appearance and Bot faces as segmented choices that sa…
jerelvelarde Oct 31, 2026
b02dce0
fix(theme): the nav size is a step of its own above body text
jerelvelarde Oct 31, 2026
a946020
fix(orb): a mark given a size that isn't px draws at its default inst…
jerelvelarde Oct 31, 2026
0f87b3a
fix(orb): a cancelled touch lets go of the eyes, and one broken orb s…
jerelvelarde Oct 31, 2026
79f2fc2
fix(onboarding): example Bots are named once, by their heading
jerelvelarde Oct 31, 2026
b5f7159
test(orb): a small orb's change of state starts at the orb's clock
jerelvelarde Oct 31, 2026
4beb745
fix(orb): the eyes' and the check's shadows are as soft on a 1x scree…
jerelvelarde Nov 2, 2026
e5db192
feat(setup): a setup checklist the server answers for each reader
jerelvelarde Oct 29, 2026
98b2e8b
feat(onboarding): a connection started in onboarding comes back to it
jerelvelarde Oct 29, 2026
e0896ce
feat(onboarding): a step frame that is two panes on a desktop
jerelvelarde Oct 29, 2026
df3b705
feat(onboarding): a picture for each step of the intro
jerelvelarde Oct 29, 2026
8cd32c9
feat(onboarding): connect apps, get notified and check your setup
jerelvelarde Oct 29, 2026
417dc7e
feat(onboarding): first run is a set of steps, not a looping intro
jerelvelarde Oct 29, 2026
534e938
docs: changelog for the onboarding steps
jerelvelarde Oct 29, 2026
19d6d98
docs: the drop guard's note and the changelog say what onboarding dra…
jerelvelarde Oct 29, 2026
5423fa9
fix(onboarding): an admin with no apps is shown where to add them
jerelvelarde Oct 29, 2026
74472cd
fix(model): check a key at the provider's own address, even when it i…
jerelvelarde Oct 29, 2026
e0b40d8
fix(onboarding): say what a Bot asks about as OpenBot behaves out of …
jerelvelarde Oct 29, 2026
01c314b
fix(setup): a set-up Bot computer with none running says so
jerelvelarde Oct 29, 2026
4fb9b6e
fix(setup): a read asks again for answers that failed or are old
jerelvelarde Oct 29, 2026
37c4213
docs(onboarding): describe the steps as OpenBot's own
jerelvelarde Oct 29, 2026
2ffb3cf
fix(onboarding): a step's buttons stay on a laptop's screen
jerelvelarde Oct 30, 2026
ae1a399
fix(onboarding): check the setup before connecting apps, and keep the…
jerelvelarde Oct 31, 2026
6423ad5
fix(setup): a member's gaps are a neutral line, and loading says so
jerelvelarde Oct 31, 2026
30bc101
feat(setup): reopen the setup checklist in Settings → Setup
jerelvelarde Oct 31, 2026
43779bc
fix(onboarding): the step comes first, and its name matches its heading
jerelvelarde Oct 31, 2026
e96e4c6
fix(onboarding): the name step's button is the frame's, and reads done
jerelvelarde Oct 31, 2026
ac97488
fix(onboarding): the self-hosting step offers two actions, not four
jerelvelarde Oct 31, 2026
8c95df7
fix(onboarding): the step list says what its marks show, and rings ar…
jerelvelarde Oct 31, 2026
72a84d5
fix(onboarding): step 2 says so when there's no Bot computer
jerelvelarde Oct 31, 2026
35f5d76
fix(onboarding): pictures look like pictures, and notifications are a…
jerelvelarde Oct 31, 2026
cbd59ef
feat(onboarding): turn on Ask before making changes from the approval…
jerelvelarde Oct 31, 2026
86625bb
docs: the changelog and checklist say what onboarding does now
jerelvelarde Oct 31, 2026
142f0e0
fix(onboarding): the list of steps is wide enough for every step's name
jerelvelarde Oct 31, 2026
55ee08c
test(onboarding): the decorative-face check follows the roster into t…
jerelvelarde Oct 31, 2026
17f34cc
fix(onboarding): Continue on Get notified asks for the name, never fi…
jerelvelarde Nov 2, 2026
aa92499
fix(onboarding): Get notified in the desktop app says notifications a…
jerelvelarde Nov 2, 2026
a191389
feat(sidebar): rows that lift under the pointer, a row menu and ⌘K
jerelvelarde Oct 28, 2026
4af686d
feat(chat): a reply in bubbles, and tool lines that say how a step went
jerelvelarde Oct 28, 2026
276fb26
feat(chat): the composer and an orb in the conversation header
jerelvelarde Oct 28, 2026
52b9e1b
feat(computer): the Bot's computer beside the chat, with its steps
jerelvelarde Oct 28, 2026
7b4270e
fix(chat): inset the composer from the conversation column's edges
jerelvelarde Oct 28, 2026
1ca7ee8
fix(chat): a declined or refused browser step reads as one
jerelvelarde Oct 28, 2026
307aa42
fix(chat): a browser step that didn't happen says what it would do
jerelvelarde Oct 28, 2026
17d1bb2
feat(approvals): a card that says what a Bot will do, and folds to wh…
jerelvelarde Oct 29, 2026
69663aa
feat(chat): every conversation says its Bots are AI and can make mist…
jerelvelarde Oct 29, 2026
83d689c
fix(chat): name a browser step for what it did, not "Used the browser"
jerelvelarde Oct 29, 2026
7e4c2c7
fix(approvals): a browser step's card is titled as its step, and yes …
jerelvelarde Oct 29, 2026
d2949ad
fix(approvals): a longer field name keeps to one line on the card
jerelvelarde Oct 29, 2026
54df05e
fix(chat): a browser step that hasn't happened is named as a whole ph…
jerelvelarde Oct 29, 2026
4811c9e
fix(approvals): say how far Always allow here reaches, and never hide…
jerelvelarde Oct 29, 2026
96fdf33
fix(computer): the password box promises the page, not a site it can'…
jerelvelarde Oct 29, 2026
5bc5bb9
fix(chat): a call tried again after a decline reads declined, and one…
jerelvelarde Oct 29, 2026
f76e77c
fix(approvals): a conversation polls its approvals once, however many…
jerelvelarde Oct 29, 2026
8f661a7
fix(chat): the orb doesn't smile done while the conversation needs you
jerelvelarde Oct 29, 2026
f047677
test(chat): a declined step's missing output is asserted on the step …
jerelvelarde Oct 29, 2026
5d4bbaa
docs(chat): the changelog says the password box promises the page
jerelvelarde Oct 30, 2026
a025587
fix(approvals): a browser step's card names the element and the page …
jerelvelarde Oct 31, 2026
82e775c
fix(approvals): a broad Always allow here reads as a caution, and say…
jerelvelarde Oct 31, 2026
2565a1e
fix(chat): a conversation waiting on you says so on its row, and Need…
jerelvelarde Oct 31, 2026
46b1214
fix(chat): a failure reads in the problem colour, and a landed step r…
jerelvelarde Oct 31, 2026
97f6308
fix(approvals): a decided card keeps focus on its title, and each wai…
jerelvelarde Oct 31, 2026
3193d0e
fix(chat): the header announces state changes and settled steps, not …
jerelvelarde Oct 31, 2026
8e0287c
fix(chat): a done browser step reads as a whole phrase
jerelvelarde Oct 31, 2026
1223740
fix(chat): a heading or a label stays with what follows, and no bubbl…
jerelvelarde Oct 31, 2026
75284f3
fix(chat): a step just allowed reads as working until it lands
jerelvelarde Oct 31, 2026
c9f1a7c
fix(chat): the AI notice names the Bot you are talking to
jerelvelarde Oct 31, 2026
f96b778
fix(chat): a hand-off the person declined reads as declined, not refused
jerelvelarde Oct 31, 2026
250a7c7
fix(approvals): a card the server holds appears when the turn ends, n…
jerelvelarde Oct 31, 2026
f9601fd
fix(approvals): a card is matched to its call by thread as well as ca…
jerelvelarde Oct 31, 2026
ac5e0f4
test(sidebar): the pagination test answers the roster's inbox poll
jerelvelarde Oct 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .claude/skills/openbot-screen-layout/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,11 @@ itself when the dialog changes something.

## Units

The root is the browser's 16px, so Tailwind's spacing, sizes and widths are their documented values
(`p-4` is 16px, `max-w-3xl` is 768px) and land on its 4px grid. Text is the exception: `styles.css`
sets every `--text-*` to Tailwind's default times 15/16, so `text-sm` is 13.125px and body text is
15px. That is the scale this app has always read at; do not size text in px or rem by hand to match
the docs.
The root is the browser's 16px, so Tailwind's spacing, sizes, widths and text sizes are their
documented values (`p-4` is 16px, `max-w-3xl` is 768px, `text-sm` is 14px) and land on its 4px grid.
Text used to be the exception, on a 15px scale of its own; it is not any more. Where a screen needs one
of the named sizes, use the five `type-*` utilities in `theme.css`; do not size text in px or rem by
hand.

Even so, never hardcode a pixel constant derived from a Tailwind token, and never compute a ratio
from one. Measure the element — `offsetWidth`, `clientWidth`, a `ResizeObserver` — and scale from what
Expand Down
66 changes: 66 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,72 @@ again when they come back to the end or press the arrow. A rail beside a convers
per turn: hovering one previews what was asked and answered, and choosing it goes there. Nothing
changes for a deployment.

### First run shows what OpenBot does, one step at a time

- The looping intro is replaced by steps that show what OpenBot does (a browser and files of its
own, a team of Bots, and asking before it acts, with Ask before making changes offered right
there), then Check your setup, Connect your apps, Get notified, and the name step, whose Get
started opens the app. On a desktop each step's words sit beside a picture of it, under one line
saying where the person is ("Step 5 of 9") that opens the list of steps; on a phone they come one
at a time. A reload, browser Back and a connection's return all keep the person's place, which is
now saved as they go. A link on a step to another page moves on to the next step and opens that
page once onboarding is done.
- Check your setup asks the new `GET /api/setup` whether Intelligence, the model key, the Bot computer,
more apps and Slack and Teams work, row by row. An admin, or somebody running OpenBot alone, is
shown the page or the variables that close a gap; everybody else only that their admin sets it up,
with no warning colours. An admin can reopen the same checklist afterwards in Settings → Setup, to
check again after setting a variable and restarting OpenBot.
Check again asks Intelligence and the model provider again, at most every 10 seconds. Reading the
checklist does the same once an answer has failed or is five minutes old, without waiting for it,
so the next read has the new answer. To check the Bot computer, the server sends each running
computer its network policy whenever it asks, and sees that it answers; it wakes none.
- An app connected from Connect your apps comes back to that step from the app's own sign-in page,
whether it connected, failed or was cancelled there. A connection started from Connections or an
app's admin page comes back where it did before.

### OpenBot has a new look

- Every screen has new colours: cool neutral greys, a near-black primary button that turns light
in dark mode, a purple focus ring, slightly rounder corners and quicker easing. Text now follows
the browser's own size, so it is a little larger than before.
- Dark mode follows the system by default. Settings → General → Appearance offers System, Light and
Dark, kept in this browser. Someone who had turned the old dark switch on stays dark.
- Every Bot, and OpenBot's own mark, is an orb with eyes that blinks and follows the pointer. It
holds still with reduced motion.
- Each Bot's orb takes its colour and pattern from the Bot, so two Bots in one colour still look
different. Violet is kept for OpenBot's own mark.
- The sidebar takes the same look, with OpenBot's orb beside its name. A row lifts to a card under
the pointer and while it is open, and you can always see where the keyboard is. While a Bot is
working, its orb in the list shows it, and so does a still blue dot. Each conversation has a "…"
button with Pin and Delete, which used to be on right-click alone. ⌘K, or Ctrl+K, opens the
sidebar and puts you in its search box.
- A conversation reads like a chat. A Bot's reply arrives one bubble per thought, and a bubble holding
a code block or a table takes the full width on a wide screen; your messages sit in a tinted bubble,
and three dots show a Bot thinking. A step is marked done only when it worked: one that was refused,
failed or declined by you is named for what it would have done ("Send your email"), and one held on
its approval card says it is waiting for you. Mail and calendar steps, through any app, are named
for what happened to yours ("Searched your email").
- A conversation with one Bot shows that Bot's orb in its header. The orb works while the Bot does,
watches while you type, and smiles when an answer lands. Under the conversation's name, "Working ·
Searching the web" says which step the Bot is on, and "Needs you" says an approval is waiting there.
A run that goes on after you allow something shows as working too. The message box is a rounded
pill with larger buttons, and it says "Message" and the Bot's name until you type.
- A Bot's computer opens in a wider pane beside the conversation. Its header shows the Bot's orb,
whose computer it is and Take control, with a dot while the conversation needs you. Under the
screen, every step the Bot took in its browser, approved clicks included, sits among the commands
it ran, newest last, marked done, waiting for you or didn't work. The pane opens by itself only
when it fits beside the conversation; on a narrow screen the computer button lights up instead.
The box for a password or a code says the value goes straight to the page and the Bot never sees
it.
- When a Bot asks before acting, its card says in plain words what it will do, in which app or
where, to whom, and what it will send, with everything else under Details. Decline and Allow once
answer it, and a quieter Always allow here saves a rule for that Bot, action and place; a step
handed to you asks "I did it myself" or "Don't do it". The same card is in the conversation, on
the Bot's page and in the list of what needs you. Once you answer, it folds to how it went
(Allowed, Sent, Done, Declined, Didn't work) and says who decided. A request for a step that is
alone in its turn now shows in the conversation too, where before it waited only on the Bot's
page. Under the message box, every conversation says that OpenBot is AI and can make mistakes.

### Generated interfaces use A2UI 1.0

With generative UI on, a Bot builds an interface from CopilotKit's standard catalog on A2UI 1.0
Expand Down
24 changes: 18 additions & 6 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,27 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OpenBot</title>
<!-- Sets the theme before the first paint. Must stay inline and classic: `defer` or `type="module"` runs too late. -->
<!-- The rule in src/lib/theme.ts (parseThemePreference, then resolveTheme): the person's choice, else the system's setting. -->
<script>
// localStorage throws in some privacy modes; a theme is not worth taking the app down for.
try {
const dark = window.localStorage.getItem("openbot-theme") === "dark";
(() => {
let choice = null;
// localStorage throws in some privacy modes; the system's setting still applies.
try {
choice = window.localStorage.getItem("openbot-appearance");
if (choice !== "system" && choice !== "light" && choice !== "dark")
choice = window.localStorage.getItem("openbot-theme") === "dark" ? "dark" : "system";
} catch {}
const dark =
choice === "dark" ||
(choice !== "light" && !!window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches);
document.documentElement.classList.toggle("dark", dark);
document.documentElement.style.colorScheme = dark ? "dark" : "light";
const skin = window.localStorage.getItem("openbot-skin");
if (skin && skin !== "openbot") document.documentElement.dataset.skin = skin;
} catch {}
// The person's skin, painted before the bundle loads, the same way.
try {
const skin = window.localStorage.getItem("openbot-skin");
if (skin && skin !== "openbot") document.documentElement.dataset.skin = skin;
} catch {}
})();
</script>
</head>
<body>
Expand Down
1 change: 0 additions & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
"@tanstack/react-router": "^1.170.27",
"@tanstack/react-table": "^9.3.1",
"better-auth": "^1.6.27",
"boring-avatars": "^2.0.4",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"embla-carousel-react": "^8.6.0",
Expand Down
24 changes: 17 additions & 7 deletions app/src/components/agents/abstract-avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
import Avatar from "boring-avatars";
import { BotOrb } from "@/components/agents/orb/bot-orb";

/**
* A Bot's face: its orb, with the look its seed picks. The seed is the Bot's id unless a tenant
* package set one or the Bot was copied from another, so `ChannelAvatar`, which goes by id, matches it
* for every other Bot.
* The orb hides itself from assistive tech, so the Bot is announced once, by name. Beside a heading
* that already names the Bot, pass `decorative` and the face is hidden too, so it isn't said twice.
*
* Clipped to its circle, so its glow never spills into the row beside it or makes a list scroll.
* At rest the glow is too faint that far out to be missed.
*/
export function AbstractAvatar({
decorative = false,
name,
seed,
size = 40,
}: {
decorative?: boolean;
name: string;
seed: string;
size?: number;
}) {
return (
<span
role="img"
aria-label={name}
{...(decorative
? { "aria-hidden": true }
: { role: "img", "aria-label": name })}
className="inline-flex shrink-0 overflow-hidden rounded-full"
style={{ height: size, width: size }}
>
{/* The drawing carries its own role; hidden so the coworker is announced once, by name. */}
<span aria-hidden="true" className="contents">
<Avatar name={seed} size={size} />
</span>
<BotOrb seed={seed} size={size} />
</span>
);
}
Loading