Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
65de945
Release v1.0.0-rc.1 (#1325)
github-actions[bot] Nov 9, 2026
0154b2e
Open "OpenBot is running" on its heading, with Updates under the butt…
davidmckayv Nov 9, 2026
1b8c8f3
Reach past the newest 50 events on Activity and Admin Audit (#1326)
davidmckayv Nov 9, 2026
09dde85
Skip the narration question on a computer with no microphone (#1327)
davidmckayv Nov 9, 2026
b93699c
Fit New Bot's four named frameworks above the footer at 800px (#1328)
davidmckayv Nov 9, 2026
d38dfbd
Say which apps need a key, and where to get it, before the key form (…
davidmckayv Nov 9, 2026
2692433
Let a person connect several accounts of one app, and let their Bots …
davidmckayv Nov 9, 2026
8b5c55b
Say what happens next after a recording saves on Teach a Bot (#1302)
davidmckayv Nov 9, 2026
a0c68dc
Keep Install's bar short of full while items unpack, and say Give wor…
davidmckayv Nov 9, 2026
dfb0c9a
Release v1.0.0-rc.2 (#1330)
github-actions[bot] Nov 9, 2026
dea620f
Ask the Google Maps starter for step-by-step walking directions (#1336)
davidmckayv Nov 9, 2026
6f71a6d
Book a demo: only Not now under the calendar until a call is booked (…
davidmckayv Nov 9, 2026
e423bbc
Lay bar charts with long names on their side (#1337)
davidmckayv Nov 9, 2026
51397bb
Keep a conversation's rail of turns clear of the Bot's replies (#1338)
davidmckayv Nov 9, 2026
a21ba49
Release v1.0.0-rc.3 (#1339)
github-actions[bot] Nov 9, 2026
fb6b5e5
Tell a Bot which apps it can use, and where each stands for the perso…
davidmckayv Nov 9, 2026
bb7108c
Say which Docker resource is short for the back end, and where to rai…
davidmckayv Nov 9, 2026
e57e3f5
Let OpenBot's own 4 CPU Podman machine through the engine check befor…
davidmckayv Nov 9, 2026
ca059de
Release v1.0.0-rc.4 (#1348)
github-actions[bot] Nov 9, 2026
3684ed9
Tell a Bot where each app stands the way its page does (#1350)
davidmckayv Nov 9, 2026
d0ec63d
Release v1.0.0-rc.5 (#1351)
github-actions[bot] Nov 9, 2026
ac9c16f
Release v1.0.0 (#1352)
github-actions[bot] Nov 9, 2026
8cb73f0
Bring release/1.0 to main at e4a73d7bf for 1.0.1 (#1413)
davidmckayv Nov 10, 2026
a9a6413
Release v1.0.1-rc.1 (#1414)
github-actions[bot] Nov 10, 2026
59a7a30
Bring release/1.0 to main at 795f619bb for the next 1.0.1 candidate (…
davidmckayv Nov 10, 2026
50b39d5
Release v1.0.1-rc.2 (#1420)
github-actions[bot] Nov 10, 2026
380826f
Release v1.0.1 (#1423)
github-actions[bot] Nov 10, 2026
e64c3f8
Bring release/1.0 to main at 29b7a909f for the first 1.0.2 candidate …
davidmckayv Nov 11, 2026
de528bd
Release v1.0.2-rc.1 (#1460)
github-actions[bot] Nov 11, 2026
8c7f288
Bring release/1.0 to main at fa255b7d9 for the next 1.0.2 candidate (…
davidmckayv Nov 11, 2026
49fb010
Release v1.0.2-rc.2 (#1472)
github-actions[bot] Nov 11, 2026
929c11e
Bring release/1.0 to main at 3d9a8b17a for the next 1.0.2 candidate (…
davidmckayv Nov 11, 2026
7744874
Release v1.0.2-rc.3 (#1486)
github-actions[bot] Nov 11, 2026
cca9f60
Release v1.0.2 (#1487)
github-actions[bot] Nov 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
27 changes: 20 additions & 7 deletions .claude/skills/openbot-copy/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: openbot-copy
description: The words and the voice for every piece of text a person reads in OpenBot: screen headings and descriptions, buttons, empty states, notices, chat cards, the server's error and refusal messages that reach the browser, and OpenBot Desktop's setup window, Status window and menus. Holds the glossary (Bot, app, admin, OpenBot, and the parts of OpenBot: front end, back end, database) and the style rules. Use when writing or changing any text that is shown to a person, naming a screen, a section, a button or a state, writing an error or refusal message, or reviewing a diff that adds user-facing strings under app/src, server/src, desktop/src or desktop/src-tauri. Don't use for text written for the model (tool descriptions, standing instructions, system prompts), for code comments, or for the docs under docs/.
description: The words and the voice for every piece of text a person reads in OpenBot: screen headings and descriptions, buttons, empty states, notices, chat cards, the server's error and refusal messages that reach the browser, and OpenBot Desktop's setup window, Status window and menus. Holds the glossary (Bot, app, admin, OpenBot, and the parts of OpenBot: front end, backend, database) and the style rules. Use when writing or changing any text that is shown to a person, naming a screen, a section, a button or a state, writing an error or refusal message, or reviewing a diff that adds user-facing strings under app/src, server/src, desktop/src or desktop/src-tauri. Don't use for text written for the model (tool descriptions, standing instructions, system prompts), for code comments, or for the docs under docs/.
---

# OpenBot Copy
Expand Down Expand Up @@ -29,23 +29,34 @@ One word for one thing, everywhere a person can see it.
| **Capabilities** | Your skills and your Bots' memory of you, and the page with both. | plugins |
| **skill** | A named instruction invoked with `/`. | command, prompt |
| **admin** | The person who runs OpenBot for everybody. | administrator, owner, operator |
| **OpenBot** | The product the person is using. | this deployment, the server, the instance |
| **OpenBot** | The product the person is using, and their account with it: "Sign in to OpenBot", "your OpenBot account". | this deployment, the server, the instance, CopilotKit |
| **OpenBot by CopilotKit** | The company, only where it has to be named: the license agreement's name, a legal or privacy line, the one place setup says who makes OpenBot. | CopilotKit alone |
| **turn on / turn off** | An admin switching an app or a feature. | enable / disable (in sentences; a switch may still read "Enabled") |
| **conversation** | A thread with one or more Bots. | channel, chat (in sentences) |
| **front end** | The part of OpenBot a person opens in the browser. | the web app, the UI |
| **back end** | The part of OpenBot that runs the Bots and keeps conversations, memory, learning and Skills. | Intelligence, CopilotKit Intelligence, the platform, the stack, cpki |
| **back end dashboard** | The back end's own pages, where Learning and projects are managed. | the Intelligence dashboard |
| **backend** | The part of OpenBot that runs the Bots and keeps conversations, memory, learning and Skills. One word, "Backend" at the start of a sentence. | back end, Intelligence, CopilotKit Intelligence, the platform, the stack, cpki |
| **backend dashboard** | The backend's own pages, where Learning and projects are managed. | the Intelligence dashboard |
| **database** | Where OpenBot keeps its data. | Postgres (outside Admin) |
| **the computers Bots work on**, **Bot computer** | Where a Bot browses and works with files. | sandbox, container |

**Never say Intelligence.** To a person, admins included, it is all OpenBot. Name the part of
OpenBot instead: "The back end is starting.", "Waiting for the back end", "Couldn't reach the back
end. Try again." Name a feature by what it does (Automatic learning, Memory, Skills), and say
OpenBot instead: "The backend is starting.", "Waiting for the backend", "Couldn't reach the
backend. Try again." Name a feature by what it does (Automatic learning, Memory, Skills), and say
"OpenBot proposes skills", not who inside OpenBot does. An env var an admin sets keeps its name
(`INTELLIGENCE_API_URL`); the word on its own does not appear. Logs, comments, code and the operator
docs under `docs/` and `charts/` are not shown to a person and may name it.
`tests/no-intelligence-in-user-copy.test.ts` fails on a shown string that says it.

**OpenBot Desktop's first screen says self-contained.** "This version of OpenBot is fully
self-contained and runs entirely on your computer, including the OpenBot backend." The Account
step after it says only what it is for: "OpenBot needs a free license key. Sign in to get one."
Neither names Intelligence.

**Never "CopilotKit" alone.** Product copy says OpenBot, or "OpenBot by CopilotKit" where the
company has to be named. Addresses (`dashboard.copilotkit.ai`, `github.com/CopilotKit/OpenBot`),
code identifiers, env names, log lines and Copy diagnostics keep their spelling.
tests/no-intelligence-in-user-copy.test.ts and tests/plain-setup-words.test.ts hold every screen to it.

**Admin is allowed exact names.** An admin page may name `COMPOSIO_API_KEY`, OAuth and "deployment",
because the admin is the one who sets them. A page anybody can open may not.

Expand Down Expand Up @@ -86,9 +97,11 @@ because the admin is the one who sets them. A page anybody can open may not.
| "agent" or "coworker" for a Bot | Bot |
| "administrator" | admin |
| "this deployment" on a page anybody can open | OpenBot, or say what is missing |
| "CopilotKit" alone: "Sign in to CopilotKit", "your CopilotKit account" | OpenBot, or "OpenBot by CopilotKit" where the company must be named |
| A sentence over ~25 words | Split it, or cut the clause that justifies the screen |
| "rather than", an em dash, "which is" in UI text | Rewrite as two short sentences |
| A description beginning "The apps…", "What…", "Who…", or "Where…" without a main verb | State the action or behavior in a complete sentence; remove redundant explanation |
| An env var, OAuth, Composio or "grant" outside Admin | Say what the person sees |
| "Intelligence", "CopilotKit Intelligence" or "the Intelligence stack" anywhere | Name the part: the back end, the front end, the database |
| "Intelligence", "CopilotKit Intelligence" or "the Intelligence stack" anywhere | Name the part: the backend, the front end, the database |
| A test asserting long explanatory copy | Assert the short sentence, or the role and the key words |
| "CopilotKit Intelligence" on OpenBot Desktop's Account step | Allowed there only, in the one lede `SHOWN_BY_DECISION` lists (above) |
27 changes: 27 additions & 0 deletions .github/actions/test-shard/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Test shard
description: >-
Gives the steps after it TEST_SHARD, so `bun run test:ci` runs only this runner's slice of the
suite, and TEST_COUNT_DIR, where it writes that slice's test count for the `tests` check.

# Why an action and not the job's `env:`. The upstream upgrade (scripts/integrate-upstream.ts,
# ciChecks) runs the `run` steps of ci.yml's `test` job as written, on one runner, and refuses a job
# whose env or steps hold an expression. A `uses` step is the one thing it skips, so handing the
# shard over here keeps the `test` job runnable that way, including by a deployment's copy of that
# script that predates the shards, and an upgrade check still runs the whole suite in one go.

inputs:
shard:
description: This runner's shard as index/count, for example 2/4.
required: true

runs:
using: composite
steps:
- shell: bash
env:
SHARD: ${{ inputs.shard }}
run: |
{
echo "TEST_SHARD=$SHARD"
echo "TEST_COUNT_DIR=$RUNNER_TEMP/test-counts"
} >> "$GITHUB_ENV"
129 changes: 114 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,23 +149,33 @@ jobs:
- run: >-
bun test tests/sign-in.test.ts tests/session-cookies.test.ts tests/follows-popup.test.ts
tests/webrtc-proxy.test.ts tests/web-bot-auth-browser.test.ts
tests/handoff-page-restore.test.ts tests/handback-fresh-look.test.ts tests/enter-text.test.ts tests/person-browser.test.ts tests/person-browser-computer.test.ts
tests/handoff-page-restore.test.ts tests/handback-fresh-look.test.ts tests/enter-text.test.ts tests/parallel-actions-computer.test.ts tests/person-browser.test.ts tests/person-browser-computer.test.ts
tests/bot-browser.test.ts tests/bot-browser-computer.test.ts tests/recorder-capture-pass.test.ts
tests/screencast-keys-browser.test.ts tests/screencast-pacing-browser.test.ts tests/browser-memory.test.ts
working-directory: agent-computer
env:
OPENBOT_COMPUTER_BROWSER: '1'
COMPUTER_BROWSER_MODE: headless
# The app's real-browser tests, here because this job has the browser: a running step's words
# under reduced motion, where onboarding's Back lands beside the Mac window's buttons, and the name
# step's orb drawn whole under the step dashes, which only a browser's layout resolves. The root
# playwright-core is the same version as
# agent-computer's playwright, so it finds the Chromium installed above. The onboarding frame
# reads the generated app config, which `bun test` alone doesn't write (the test script's
# pretest does).
# under reduced motion, where onboarding's Back lands beside the Mac window's buttons, the name
# step's orb drawn whole under the step dashes, a conversation's rail of turns clear of the
# Bot's text, one frame around an interface drawn in a Card, the page under the update banner
# holding still as an update gets ready, and Home's message box holding still while the
# microphone's notice shows, which only a browser's layout and cascade resolve. The root
# playwright-core is the same version as agent-computer's
# playwright, so it finds the Chromium installed above. The onboarding frame reads the
# generated app config, which `bun test` alone doesn't write (the test script's pretest does).
- run: |
bun run generate:app-config
bun test app/tests/tool-line-reduced-motion.test.tsx app/tests/onboarding-window-buttons.test.tsx app/tests/onboarding-orb-room.test.tsx
bun test app/tests/tool-line-reduced-motion.test.tsx app/tests/onboarding-window-buttons.test.tsx app/tests/onboarding-orb-room.test.tsx app/tests/transcript-rail-clearance.test.tsx app/tests/a2ui-frame.test.tsx app/tests/update-banner-layout.test.tsx app/tests/composer-dictation-notice-layout.test.tsx app/tests/conversation-intro-halo.test.tsx
env:
OPENBOT_APP_BROWSER: '1'
# The desktop setup window's, for the same reason: the AI step's form holding still while the
# install behind it comes and goes. It bundles the window from the desktop's own dependencies.
- run: bun install --frozen-lockfile
working-directory: desktop
- run: bun test src/setupLayout.browser.test.ts
working-directory: desktop
env:
OPENBOT_APP_BROWSER: '1'
# Headed is the default for hosted computers, so it is tested as one: the computer starting its
Expand Down Expand Up @@ -359,9 +369,28 @@ jobs:
- name: A new values key can be absent
run: bun scripts/check-new-values-keys.ts charts/openbot/ci/${{ matrix.target }}-values.yaml

# The suite in shards, one runner each, so the run takes as long as its slowest shard rather than
# as long as every file one after another. `bun test --shard` does the split, cut by the per-file
# durations in scripts/test-timings.json so the shards take about as long as each other (dealt
# round-robin, the few files that take a minute each pile up on one runner). Every shard has its
# own database, installs and migration, so the shards share no state, and inside a shard the files
# still run one at a time because they share that one database. The `tests` job below is the
# result people read.
#
# The id stays `test` for the upstream upgrade, which runs this job's `run` steps as CI's own
# checks (scripts/integrate-upstream.ts); the shard reaches those steps through
# .github/actions/test-shard, which says why.
test:
name: tests
name: tests (shard ${{ matrix.shard }} of ${{ strategy.job-total }})
# Five shards take about three and a half minutes each on the free standard runner, so a
# larger runner would add cost without shortening the run.
runs-on: ubuntu-latest
strategy:
# Every shard runs to the end, so one red run names every failing test, not just the first
# shard's.
fail-fast: false
matrix:
shard: [1, 2, 3, 4, 5]
# The suite includes a real database integration test. Without a database it fails on every run,
# including on main, which trains everyone to read a red CI as normal. pgvector rather than plain
# postgres because the knowledge schema uses the extension.
Expand Down Expand Up @@ -389,6 +418,9 @@ jobs:
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.4.3
- uses: $/.github/actions/test-shard
with:
shard: ${{ matrix.shard }}/${{ strategy.job-total }}
- run: bun install --frozen-lockfile
# The Bots are not root workspaces and each keeps its own lockfile. The startup tests spawn
# the real entrypoint, so its dependencies have to be installed as well.
Expand Down Expand Up @@ -424,9 +456,53 @@ jobs:
with:
version: v3.19.0
- run: helm dependency build charts/openbot
# A passing job must include the expected test floor. Import-time failures can otherwise skip
# files before their tests are registered.
# This shard's tests, failing on a failed test or on a count it cannot read. The floor under the
# count is the suite's, so the `tests` job checks it on the sum of the shards.
- run: bun run test:ci
# The shard's count, and how long each of its files took.
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: test-shard-${{ matrix.shard }}
path: ${{ env.TEST_COUNT_DIR }}
if-no-files-found: error
retention-days: 1

# One result for the suite, under the name the unsharded job had. A passing job must include the
# expected test floor: import-time failures can otherwise skip files before their tests are
# registered, and a shard cannot see that, because it does not know how big it is meant to be. So
# this fails when any shard did not succeed, when any shard's count is missing, and when the counts
# add up to less than the floor (scripts/test-floor.ts).
test-total:
name: tests
runs-on: ubuntu-latest
# Also when a shard failed, so this reports the failure rather than being skipped, which a
# required check would read as a pass.
if: always()
needs: [test]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.4.3
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
pattern: test-shard-*
path: ${{ runner.temp }}/test-counts
merge-multiple: true
- name: The shards passed and add up to the floor
env:
SHARDS_RESULT: ${{ needs.test.result }}
run: bun scripts/test-ci-aggregate.ts "$RUNNER_TEMP/test-counts" "$RUNNER_TEMP/test-timings.json"
# This run's per-file durations, to download over scripts/test-timings.json when the shards
# drift out of balance.
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: test-timings
path: ${{ runner.temp }}/test-timings.json
if-no-files-found: ignore
retention-days: 14

startup:
name: startup (${{ matrix.os }})
Expand All @@ -447,7 +523,10 @@ jobs:

python-harness:
name: python harness regressions
runs-on: ubuntu-latest
# CPU-bound: runs on a 16-core larger runner (org runner group openbot-larger, billed per
# minute) for main, releases and pull requests from this repository. Pull requests from forks
# stay on the free standard runner.
runs-on: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && 'ubuntu-latest' || 'openbot-ubuntu-16core' }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand Down Expand Up @@ -547,6 +626,25 @@ jobs:
- run: docker compose --env-file /dev/null --profile harness config --format json >/dev/null
env:
PICKED_HARNESS_IMAGE: openbot-agent-langgraph-agui:test
# Docker Desktop shipped Compose v2.24.5 in early 2024, and that version refuses the whole
# project when any service's image is blank, profile or not. The desktop app runs
# `compose config` before it starts, so this is the oldest Compose it has to get past.
- name: Compose v2.24.5 reads the file with no harness picked
run: |
set -euo pipefail
case "$(uname -m)" in
x86_64) arch=x86_64; sum=94355be1d1d395040bbda1490f98d5c7627c30798a7955e1f2a78fda33a4b3e1 ;;
aarch64) arch=aarch64; sum=535e90ff9a7f24384f8a38f9f9ad49125485af7ae5ffda7226d091e5b8126948 ;;
*) echo "no pinned Compose v2.24.5 for $(uname -m)" >&2; exit 1 ;;
esac
compose="$RUNNER_TEMP/docker-compose-2.24.5"
curl -fsSL --retry 3 -o "$compose" "https://github.com/docker/compose/releases/download/v2.24.5/docker-compose-linux-$arch"
echo "$sum $compose" | sha256sum -c -
chmod +x "$compose"
"$compose" version
unset PICKED_HARNESS_IMAGE
"$compose" -f docker-compose.yml -f desktop/src-tauri/telemetry.compose.yml --env-file /dev/null config --format json >/dev/null
PICKED_HARNESS_IMAGE=openbot-agent-langgraph-agui:test "$compose" --env-file /dev/null --profile harness config --format json >/dev/null

build:
name: build
Expand Down Expand Up @@ -599,13 +697,14 @@ jobs:
# them typecheck, lint and test perfectly.
image:
name: image
runs-on: ubuntu-latest
runs-on: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && 'ubuntu-latest' || 'openbot-ubuntu-16core' }}
# The only slow job: it builds the container and boots it, ~14 minutes. The four checks above are
# seconds and stay on every push, because they catch most things cheaply. This one is the cost, so
# on a pull request it runs only when an admin adds the `full-ci` label — the point at which the PR
# is actually a merge candidate. On main and through the release workflow_call it always runs, so
# nothing reaches a release without it. `verify` treats a skipped job as passing, so an unlabelled
# PR is green on the cheap checks alone.
# PR is green on the cheap checks alone. It runs on the 16-core larger runner everywhere except
# pull requests from forks, which stay on the free standard runner.
if: >-
github.event_name != 'pull_request' ||
contains(github.event.pull_request.labels.*.name, 'full-ci')
Expand Down Expand Up @@ -914,7 +1013,7 @@ jobs:
name: verify
runs-on: ubuntu-latest
if: always()
needs: [static, deployables, mobile, computer-browser, chart, test, startup, python-harness, build, migrations, image, component-dockerfiles]
needs: [static, deployables, mobile, computer-browser, chart, test, test-total, startup, python-harness, build, migrations, image, component-dockerfiles]
steps:
- name: Require every check
env:
Expand Down
Loading
Loading