From c79d347abe03ebdbe50b5819c3a441f1724be066 Mon Sep 17 00:00:00 2001 From: Dotta <34892728+cryppadotta@users.noreply.github.com> Date: Fri, 26 Jun 2026 12:01:02 -0500 Subject: [PATCH] Update company creation copy (#8653) ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The onboarding and company switcher UI are the first places users create or select an organization > - Some of that surface still used older team/workspace wording even though the product model is company-centric > - Mixed wording makes the setup path feel inconsistent and can make users wonder whether they are creating a team, workspace, or company > - This pull request updates the affected UI copy to consistently say company > - The benefit is a clearer first-run and navigation experience without changing behavior ## Linked Issues or Issue Description No public issue exists for this small UI polish change. ### Problem or motivation The company creation and switcher surfaces used mixed team/workspace/company wording for the same concept, which makes the setup path feel inconsistent. ### Proposed solution Update the visible copy, accessibility label, inline comment, e2e expectations, and matching test expectations to use company-centric language consistently. ### Alternatives considered Leave the existing wording alone, but that preserves inconsistent terminology in a high-traffic setup path. ### Roadmap alignment This is focused UI polish and does not overlap with a roadmap-level core feature. ### Additional context The create action keeps its trailing ellipsis because it opens the onboarding wizard rather than completing immediately. ## What Changed - Updated front door and onboarding wizard labels from team-oriented copy to company-oriented copy. - Updated the sidebar company menu from workspace/team wording to company wording, including the trigger accessibility label and empty fallback text. - Kept the sidebar create action ellipsis for the dialog/wizard affordance. - Updated component and Playwright test expectations for the new copy. ## Verification - `pnpm exec vitest run ui/src/components/SidebarCompanyMenu.test.tsx` - Attempted `npx playwright test --config tests/e2e/playwright.config.ts tests/e2e/onboarding.spec.ts tests/e2e/nux-phase4-screenshots.spec.ts tests/e2e/planning-mode-visual-verification.spec.ts tests/e2e/conference-room-typing-intro.spec.ts`; local browser launch is blocked by missing host Chromium dependencies (`libatk1.0-0t64`, `libatspi2.0-0t64`, `libxcomposite1`, `libxdamage1`, `libxfixes3`, `libxrandr2`, `libgbm1`, `libasound2t64`). - Screenshots intentionally omitted because this is a copy-only change and no design screenshots are needed for review. ## Risks Low risk. This is copy-only UI polish plus matching test updates; no data model, API, migration, workflow, lockfile, or behavior changes are included. ## Model Used OpenAI GPT-5 Codex (`gpt-5`) via the Paperclip Codex agent, with tool-assisted repository inspection, GitHub CLI usage, and local command execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip --- .../e2e/conference-room-typing-intro.spec.ts | 4 ++-- tests/e2e/nux-phase4-screenshots.spec.ts | 14 ++++++------- tests/e2e/onboarding.spec.ts | 6 +++--- .../planning-mode-visual-verification.spec.ts | 4 ++-- ui/src/components/FrontDoor.tsx | 2 +- ui/src/components/OnboardingWizard.tsx | 12 +++++------ ui/src/components/Sidebar.test.tsx | 2 +- ui/src/components/SidebarCompanyMenu.test.tsx | 20 +++++++++---------- ui/src/components/SidebarCompanyMenu.tsx | 10 +++++----- ui/src/pages/BoardChat.tsx | 2 +- 10 files changed, 38 insertions(+), 38 deletions(-) diff --git a/tests/e2e/conference-room-typing-intro.spec.ts b/tests/e2e/conference-room-typing-intro.spec.ts index 0a3bd134ab..e1a7096ed6 100644 --- a/tests/e2e/conference-room-typing-intro.spec.ts +++ b/tests/e2e/conference-room-typing-intro.spec.ts @@ -60,10 +60,10 @@ test.describe("Dashboard launch after onboarding wizard", () => { if (await startBtn.count()) await startBtn.first().click(); // Step 0: front door (skipped when the wizard opens on the create path). - const frontDoor = page.getByText("Build a new team"); + const frontDoor = page.getByText("Build a new company"); if (await frontDoor.count()) await frontDoor.first().click(); - // Step 1: team name. + // Step 1: company name. await page.getByPlaceholder("Acme Corp").fill(COMPANY_NAME); await page.getByRole("button", { name: /^Next/ }).click(); diff --git a/tests/e2e/nux-phase4-screenshots.spec.ts b/tests/e2e/nux-phase4-screenshots.spec.ts index 3a4b559a7d..4c3a3481be 100644 --- a/tests/e2e/nux-phase4-screenshots.spec.ts +++ b/tests/e2e/nux-phase4-screenshots.spec.ts @@ -10,7 +10,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); * * Boots a throwaway local_trusted instance (see playwright.config.ts webServer) * and captures screenshots of every surface integrated by NUX Phases 1–3: - * - "Build a new team" step 1 (team name) + step 2 (mission) + * - "Build a new company" step 1 (company name) + step 2 (mission) * - Team-lead hire step (capsule wizard, PAP-125) * - Onboarding front door (path picker) * - "Add agents to your org" growth intake @@ -57,16 +57,16 @@ test.describe("NUX Phase 4 visual QA", () => { const baseUrl = "http://127.0.0.1:" + (process.env.PAPERCLIP_E2E_PORT ?? "3199"); - // ── Section A: create-team path (name → mission → hire) ─────────────── + // ── Section A: create-company path (name → mission → hire) ──────────── await openWizard(page); // Front door shows when the wizard doesn't open directly on the create // path (e.g. another spec already created a company on this instance). - const createCard = page.getByRole("button", { name: /Build a new team/ }); + const createCard = page.getByRole("button", { name: /Build a new company/ }); if (await createCard.count()) { await createCard.first().click(); } await expect( - page.getByRole("heading", { name: "Name your team" }), + page.getByRole("heading", { name: "Name your company" }), ).toBeVisible({ timeout: 15_000 }); await page.getByPlaceholder("Acme Corp").fill("QA Robotics"); await page.screenshot({ path: shot("02-create-name.png") }); @@ -110,7 +110,7 @@ test.describe("NUX Phase 4 visual QA", () => { page.getByRole("heading", { name: "Welcome to Paperclip" }), ).toBeVisible({ timeout: 10_000 }); await expect( - page.getByRole("heading", { name: "Build a new team" }), + page.getByRole("heading", { name: "Build a new company" }), ).toBeVisible(); await expect( page.getByRole("heading", { name: "Add agents to your org" }), @@ -118,9 +118,9 @@ test.describe("NUX Phase 4 visual QA", () => { await page.screenshot({ path: shot("01-front-door.png") }); await page.getByRole("button", { name: /Add agents to your org/ }).click(); - // The grow path shares step 1 (team name) before its step-2 intake. + // The grow path shares step 1 (company name) before its step-2 intake. await expect( - page.getByRole("heading", { name: "Name your team" }), + page.getByRole("heading", { name: "Name your company" }), ).toBeVisible({ timeout: 10_000 }); await page.getByPlaceholder("Acme Corp").fill("QA Robotics Grow"); await page.getByRole("button", { name: /^Next/ }).click(); diff --git a/tests/e2e/onboarding.spec.ts b/tests/e2e/onboarding.spec.ts index 2532b24260..eb46e76e50 100644 --- a/tests/e2e/onboarding.spec.ts +++ b/tests/e2e/onboarding.spec.ts @@ -48,14 +48,14 @@ test.describe("Onboarding wizard", () => { if (await startBtn.count()) { await startBtn.first().click(); } - const createCard = page.getByRole("button", { name: /Build a new team/ }); + const createCard = page.getByRole("button", { name: /Build a new company/ }); if (await createCard.count()) { await createCard.first().click(); } - // Step 1 — Name your team. + // Step 1 — Name your company. await expect( - page.getByRole("heading", { name: "Name your team" }), + page.getByRole("heading", { name: "Name your company" }), ).toBeVisible({ timeout: 15_000 }); await page.getByPlaceholder("Acme Corp").fill(COMPANY_NAME); await page.getByRole("button", { name: /^Next/ }).click(); diff --git a/tests/e2e/planning-mode-visual-verification.spec.ts b/tests/e2e/planning-mode-visual-verification.spec.ts index 84026eb9f2..65be76312d 100644 --- a/tests/e2e/planning-mode-visual-verification.spec.ts +++ b/tests/e2e/planning-mode-visual-verification.spec.ts @@ -44,10 +44,10 @@ test("captures planning mode UI for desktop and mobile", async ({ page }) => { const startBtn = page.getByRole("button", { name: /Start Onboarding|New Company|Add Agent/ }); if (await startBtn.count()) await startBtn.first().click(); - const createCard = page.getByRole("button", { name: /Build a new team/ }); + const createCard = page.getByRole("button", { name: /Build a new company/ }); if (await createCard.count()) await createCard.first().click(); - await expect(page.getByRole("heading", { name: "Name your team" })).toBeVisible({ timeout: 15_000 }); + await expect(page.getByRole("heading", { name: "Name your company" })).toBeVisible({ timeout: 15_000 }); await page.locator('input[placeholder="Acme Corp"]').fill(companyName); await page.getByRole("button", { name: /^Next/ }).click(); diff --git a/ui/src/components/FrontDoor.tsx b/ui/src/components/FrontDoor.tsx index 51ca886f8d..9aa8984528 100644 --- a/ui/src/components/FrontDoor.tsx +++ b/ui/src/components/FrontDoor.tsx @@ -30,7 +30,7 @@ export function FrontDoor({ onChoose }: FrontDoorProps) {
-

Build a new team

+

Build a new company

Begin with a mission, bring on a lead agent, and grow a team of agents to do the work.

diff --git a/ui/src/components/OnboardingWizard.tsx b/ui/src/components/OnboardingWizard.tsx index 80691ce891..f7c6eaac08 100644 --- a/ui/src/components/OnboardingWizard.tsx +++ b/ui/src/components/OnboardingWizard.tsx @@ -964,7 +964,7 @@ export function OnboardingWizard() {
)} - {/* Step 1: Name your team (both paths) */} + {/* Step 1: Name your company (both paths) */} {step === 1 && (
@@ -972,9 +972,9 @@ export function OnboardingWizard() {
-

Name your team

+

Name your company

- What should we call your team? + What should we call your company?

@@ -987,7 +987,7 @@ export function OnboardingWizard() { : "text-muted-foreground group-focus-within:text-foreground" )} > - Team name + Company name setStep(1)} > - ← Change team name + ← Change company name )} @@ -1589,7 +1589,7 @@ export function OnboardingWizard() { {/* Review checklist — everything that's now set up */}
{[ - { label: "Team name", done: Boolean(companyName.trim()) }, + { label: "Company name", done: Boolean(companyName.trim()) }, { label: "Mission", done: Boolean(companyGoal.trim()) }, { label: "Agent created", done: Boolean(createdAgentId) }, { label: "Model connected", done: Boolean(createdAgentId) }, diff --git a/ui/src/components/Sidebar.test.tsx b/ui/src/components/Sidebar.test.tsx index 96a57d3841..6aa15be867 100644 --- a/ui/src/components/Sidebar.test.tsx +++ b/ui/src/components/Sidebar.test.tsx @@ -410,7 +410,7 @@ describe("Sidebar", () => { expect(container.querySelector('button[aria-label="Expand sidebar"]')).toBeNull(); expect(container.querySelector('a[aria-label="Open search"]')).toBeNull(); - // The company menu (workspace switcher / logo) is still present in the rail. + // The company menu (company switcher / logo) is still present in the rail. expect(container.textContent).toContain("Company menu"); flushSync(() => { diff --git a/ui/src/components/SidebarCompanyMenu.test.tsx b/ui/src/components/SidebarCompanyMenu.test.tsx index 3b4341b1ef..7b35daf002 100644 --- a/ui/src/components/SidebarCompanyMenu.test.tsx +++ b/ui/src/components/SidebarCompanyMenu.test.tsx @@ -140,7 +140,7 @@ describe("SidebarCompanyMenu", () => { vi.clearAllMocks(); }); - it("uses team-centric create copy without the chat flag", async () => { + it("uses company-centric create copy without the chat flag", async () => { const root = createRoot(container); const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -156,7 +156,7 @@ describe("SidebarCompanyMenu", () => { await flushReact(); await flushReact(); - const trigger = container.querySelector('button[aria-label="Open Acme Labs workspace switcher"]'); + const trigger = container.querySelector('button[aria-label="Open Acme Labs company switcher"]'); expect(trigger).not.toBeNull(); act(() => { trigger?.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true, button: 0 })); @@ -164,7 +164,7 @@ describe("SidebarCompanyMenu", () => { }); await flushReact(); - expect(document.body.textContent).toContain("Create new team..."); + expect(document.body.textContent).toContain("Create new company..."); expect(document.body.textContent).not.toContain("Add company..."); act(() => { @@ -190,7 +190,7 @@ describe("SidebarCompanyMenu", () => { expect(container.textContent).toContain("Acme Labs"); - const trigger = container.querySelector('button[aria-label="Open Acme Labs workspace switcher"]'); + const trigger = container.querySelector('button[aria-label="Open Acme Labs company switcher"]'); expect(trigger).not.toBeNull(); act(() => { @@ -199,11 +199,11 @@ describe("SidebarCompanyMenu", () => { }); await flushReact(); - expect(document.body.textContent).toContain("Switch workspace"); + expect(document.body.textContent).toContain("Switch company"); expect(document.body.textContent).toContain("Edit"); expect(document.body.textContent).toContain("Strata"); expect(document.body.textContent).toContain("ANA"); - expect(document.body.textContent).toContain("Create new team..."); + expect(document.body.textContent).toContain("Create new company..."); expect(document.body.textContent).toContain("Invite people to Acme Labs"); expect(document.body.textContent).toContain("Company settings"); expect(document.body.textContent).toContain("Sign out"); @@ -224,7 +224,7 @@ describe("SidebarCompanyMenu", () => { }); }); - it("toggles company order editing without selecting a workspace", async () => { + it("toggles company order editing without selecting a company", async () => { const root = createRoot(container); const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, @@ -240,7 +240,7 @@ describe("SidebarCompanyMenu", () => { await flushReact(); await flushReact(); - const trigger = container.querySelector('button[aria-label="Open Acme Labs workspace switcher"]'); + const trigger = container.querySelector('button[aria-label="Open Acme Labs company switcher"]'); expect(trigger).not.toBeNull(); act(() => { @@ -280,7 +280,7 @@ describe("SidebarCompanyMenu", () => { }); }); - it("navigates to the selected workspace dashboard from company-prefixed routes", async () => { + it("navigates to the selected company dashboard from company-prefixed routes", async () => { mockLocation.pathname = "/PAP/issues"; const root = createRoot(container); const queryClient = new QueryClient({ @@ -297,7 +297,7 @@ describe("SidebarCompanyMenu", () => { await flushReact(); await flushReact(); - const trigger = container.querySelector('button[aria-label="Open Acme Labs workspace switcher"]'); + const trigger = container.querySelector('button[aria-label="Open Acme Labs company switcher"]'); expect(trigger).not.toBeNull(); act(() => { diff --git a/ui/src/components/SidebarCompanyMenu.tsx b/ui/src/components/SidebarCompanyMenu.tsx index 87c8367c8b..3177c62356 100644 --- a/ui/src/components/SidebarCompanyMenu.tsx +++ b/ui/src/components/SidebarCompanyMenu.tsx @@ -231,12 +231,12 @@ export function SidebarCompanyMenu({ open: controlledOpen, onOpenChange }: Sideb // svg present (expanded) it was already 12px but without it (rail) it fell // back to 8px — a 4px horizontal jump on collapse (PAP-10676). className="h-9 flex-1 justify-start gap-2 px-3 text-left" - aria-label={selectedCompany ? `Open ${selectedCompany.name} workspace switcher` : "Open workspace switcher"} + aria-label={selectedCompany ? `Open ${selectedCompany.name} company switcher` : "Open company switcher"} > {selectedCompany ? : null} - {selectedCompany?.name ?? "Select workspace"} + {selectedCompany?.name ?? "Select company"} {!rail && } @@ -245,7 +245,7 @@ export function SidebarCompanyMenu({ open: controlledOpen, onOpenChange }: Sideb
- Switch workspace + Switch company
@@ -291,7 +291,7 @@ export function SidebarCompanyMenu({ open: controlledOpen, onOpenChange }: Sideb disabled={isEditingOrder} > - Create new team... + Create new company... diff --git a/ui/src/pages/BoardChat.tsx b/ui/src/pages/BoardChat.tsx index 423fbd8cf5..3cd7f98b30 100644 --- a/ui/src/pages/BoardChat.tsx +++ b/ui/src/pages/BoardChat.tsx @@ -381,7 +381,7 @@ export function BoardChat() { }, [selectedCompanyId]); // The onboarding wizard renders as an overlay above an already-mounted - // Conference Room (sidebar "Create new team..." path). Holding the reveal + // Conference Room (sidebar "Create new company..." path). Holding the reveal // timer while it's open guarantees the dots window can't burn off behind // the wizard before the user ever sees the chat (PAP-134). const { onboardingOpen } = useDialogState();