Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

console: app identity moves into the top bar — the app icon sits left of the app name in the switcher pill, dropdown rows carry icons, the sidebar logo header goes, the phone drawer header shows icon + name, and the platform mark leaves app context (maintainer ruling 2026-10-12) #12201

Closed

Description

@hotlong

Filing gate: a maintainer ruling in chat, 2026-10-12 — 「应用 logo 建议只需要一个尺寸,放在顶部导航的应用名称左侧」, then 「同意」 on the mock and on dropping the platform mark from app context. Filed from the cloud maintainer's session. ⛔ Not a claim.

What is wrong today

UnifiedSidebar renders branding.logo as a 32 px <img> alone in a SidebarHeader, with no text (objectui#10827 gave the key its only reader). HotCRM's value is a square app icon, so a HotCRM environment shows an unlabeled orange tile in a 56 px header, 80 px below the ObjectOS platform mark and the 「HotCRM ▾」 switcher pill that already carry the identity. Two brand marks in one corner, neither saying what it is. On phones the top bar is hidden, so that tile is the only thing that says which app the user is in, and it still has no name.

HotCRM environment, sidebar logo header

Ruling (maintainer, 2026-10-12)

  1. One asset. branding.logo is the app's square icon (1:1). Surfaces render it at the size they need: 22 px in the top bar pill, 22 px in the switcher dropdown, 26 px in the phone drawer, 40 px on marketplace cards. No second asset, no wordmark slot.
  2. The icon sits left of the app name in the top-bar app switcher pill. Every row of the switcher dropdown shows its app's icon. An app without branding.logo gets its icon (lucide name) drawn on a primaryColor tile at the same size, so every row has a glyph.
  3. The sidebar logo header goes away on desktop. On phones the drawer header shows icon + app name, in the place of the existing mobile-only Home row.
  4. The platform mark leaves the top bar in app context. The bar starts with the app pill. Platform surfaces (environment Home, settings) keep the ObjectOS mark. One brand mark per screen; the 「所有应用」 row in the switcher dropdown is the way back to Home.
  5. The PREVIEW stage chip moves to the right, beside the search box, so the bar's left edge is the app.
  6. The Studio entry gets a label (maintainer, 2026-10-12, 「同意」). The icon-only Hammer button (data-testid="app-design-in-studio-button", the ADR-0080 reverse bridge, admin + metadata-authoring gated) becomes an outline button 「编辑应用」 / "Edit app" with a pencil icon, placed at the left edge of the right-hand utility cluster; on narrow widths it collapses to the pencil with a tooltip. The same gate, the same deep link. The switcher dropdown gains a bottom row 「在 Studio 中编辑 」 / "Edit in Studio" next to 「所有应用」, admin-only, as the second path. 「系统设置」 stays listed as an app; Studio is never listed as one.

Mock (the maintainer's private design canvas; ask the maintainer for a render if needed): https://claude.ai/artifact/3RcJzvfgizHDpTsep32TAn — artboards: desktop top bar (tweak platformLogo to compare with/without the platform mark), switcher dropdown with fallback rows, phone drawer, icon candidates.

Where

  • packages/app-shell/src/layout/UnifiedSidebar.tsx: drop the appLogo SidebarHeader; the mobile sheet header becomes icon + name.
  • The top-bar app switcher pill and its dropdown (the component that renders 「HotCRM ▾」): icon before the label, icons per row, fallback tile.
  • Platform-mark visibility by context (app vs platform) in the top bar; PREVIEW chip placement.
  • packages/app-shell/src/layout/AppHeader.tsx: the Design-in-Studio button (label, pencil icon, responsive collapse); AppSwitcher.tsx: the admin-only Studio row.
  • Rider, same seat, a small separate PR in objectstack: the @objectstack/spec doc on branding.logo says "1:1 square app icon, SVG preferred, at least 64 px"; refuse a non-square value if the schema can express it, otherwise doc only.
  • HotCRM's own icon and color: branding: replace the app icon with the flat "H" mark and align primaryColor to its orange (#EA580C) — one asset that every surface renders (maintainer ruling 2026-10-12) hotcrm#2066 (filed with this card).

Acceptance

  1. HotCRM environment, desktop: the top bar reads [icon]HotCRM ▾ / Leads / …; no sidebar header; no ObjectOS mark in the bar. Screenshots zh-CN and en.
  2. Environment Home: ObjectOS mark present, no app pill.
  3. Switcher dropdown: every app row has a glyph; an app without branding.logo shows the fallback tile.
  4. Phone (375 px): the drawer header shows icon + 「HotCRM」; nothing else in the drawer changes.
  5. Tests: UnifiedSidebar no longer renders branding.logo; the switcher renders it; the fallback path is covered.
  6. Admin: the top bar shows 「编辑应用」 with text at 1280 px and a pencil-only button with tooltip at 768 px; the switcher dropdown ends with 「在 Studio 中编辑 HotCRM」. Member: neither appears. The existing AppHeader.designInStudioNeedsAuthoring-10899 test keeps passing against the new markup.

Related

objectui#10827 (the reader this card moves) · objectui#7256 · objectstack-ai/cloud#2772 (cloud console experience epic; this is its environment-side cousin) · objectstack-ai/cloud#2777 (the cloud home renders the same icon) · objectstack-ai/hotcrm#2066

Activity

  1. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    Triage seat (seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-12T08:04Z. ⛔ Not a claim, ⛔ not a dispatch. Grade completed: domain:ui · area:devpath added. The filer's enhancement · priority:p2 · pm:queue stand (the maintainer's ruling, 2026-10-12).

  2. added
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 12, 2026
  3. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 (executes the maintainer's ruling quoted in the card body, items 1–6: app identity moves into the top bar, the sidebar logo header goes, the phone drawer header shows icon + name, the platform mark leaves app context, the Studio entry gets a label)
    Session: session_01G5TSaEwbEQsKMjhzTB4rEd
    Account: os-warren
    Branch: claude/issue-12201-app-identity-top-bar
    Worktree: objectui-issue-12201
    Domain: domain:ui
    Seat: domain:ui#2
    File surface, on objectui main 9646e2e:


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    Rider routed · domain:ui seat 2 · session_01G5TSaEwbEQsKMjhzTB4rEd · 2026-10-12T09:04Z: the card's objectstack rider (the @objectstack/spec doc on branding.logo) is filed as objectstack-ai/objectstack#23000 for triage and the domain:spec seat. It is not part of this card's dispatch (claim 6121008577).


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
    "issue": 12201,
    "status": "done",
    "branch": "claude/issue-12201-app-identity-top-bar",
    "pr": "#12225",
    "session": "session_01G5TSaEwbEQsKMjhzTB4rEd",
    "premise_still_valid": true,
    "summary": "Ruling items 1-6 implemented in packages/app-shell/src/layout. The app pill (AppSwitcher) draws branding.logo at 22 px left of the name, and every dropdown row draws its app's glyph: the logo, or the app's icon (via the existing getIcon) on a tile in that app's own hex primaryColor, published as CSS custom properties with a dark variant, or a neutral tile when no hex is declared. A new internal AppMark plus appTileColors does this; neither is exported. UnifiedSidebar drops the branding.logo SidebarHeader. On phones the drawer header shows the glyph (26 px) and the app name, with a trailing 「All apps」 link that keeps data-testid mobile-sidebar-home and useHomePath. In the app variant AppHeader no longer draws the platform mark or a separator before the pill, the PREVIEW chip moves beside the search box, and the Studio hammer becomes an outline pencil button 「Edit app」 (text from lg, pencil plus title tooltip below; same gate, same studioDesignPath, same test id). The pill's dropdown ends with 「All apps」 (the declared home) and an admin-only 「Edit APP in Studio」 row fed AppHeader's own studioDesignPath. Three i18n keys were added to all ten packs. AppHeader.tsx relay for objectui#12198: blocks were edited in place, with nothing extracted or renamed. The logo Link is wrapped in !isApp. The left PreviewBadge is gated !isApp, and an isApp PreviewBadge is inserted above the Group 1 Search block. The app-pill block lost its two leading PathSep spans and passes designInStudioPath. The Studio button moved from after InboxPopover to the first child of Group 2. Hammer became Pencil and the cn import was dropped. The breadcrumb code is untouched and in its old place: the extraSegments computation (its routeType page branch with console.breadcrumb.pages included) sits between studioDesignPath and the JSX, and the extraSegments.map render sits between the app-pill block and the mobile page-label block.",
    "tests": "All at head c9ba7b8, after building app-shell's dependency closure (turbo run build --filter=@object-ui/app-shell^..., 28/28 successful). pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json; its include glob covers src/**/*.test.tsx, not counted with --listFiles): TYPECHECK_EXIT=0. pnpm exec vitest run packages/app-shell/src/layout/ plus homeAffordancesFollowDeclaration-7256, appSidebarRemoved-5817 and KeyboardShortcutsDialog.wiredOnly-11674: 'Test Files 64 passed (64)', 'Tests 462 passed (462)'. That covers the 3 new files (AppSwitcher.appIdentity-12201, AppHeader.appIdentity-12201, UnifiedSidebar.mobileAppHeader-12201), the rewritten ConsoleLayout.appBrandingLogo-10827 (reader assertion moved from the sidebar to the pill), and AppHeader.designInStudioNeedsAuthoring-10899, which is unchanged and green against the new markup. This is a declared narrowing; the rest of app-shell is left to CI. pnpm exec vitest run packages/i18n/: 'Test Files 83 passed (83)', 'Tests 1321 passed | 13 skipped'. pnpm --filter @object-ui/i18n type-check: exit 0. pnpm --filter @object-ui/app-shell lint && pnpm --filter @object-ui/i18n lint: lock VERDICT command-exit 0, '0 errors' in both; the new files have 0 warnings. Reverse check, run once with the fix committed: each source file was checked out at the BASE 9646e2e blob (disk hash equal to the BASE blob, anchor grep -c 0), the affected tests were run, then HEAD was restored (hash equal to the HEAD blob, git diff HEAD empty, trap restore on EXIT INT TERM). Results: UnifiedSidebar.tsx at BASE, 5 failed / 5 passed (the 4 drawer-header cases and sidebar-no-logo). AppSwitcher.tsx at BASE, 14 failed / 5 passed (every pill and row case; the appTileColors units and the unrelated controls stayed green). AppHeader.tsx at BASE, 6 failed / 6 passed (the 6 app-context cases; the platform controls, the member case and all 3 10899 cases stayed green). git status was empty after the run. NOT MEASURED: browser screenshots, reason: no ObjectStack backend can run here (the ../objectstack checkout has no node_modules or dist, and building one is a full install and build on a shared 4-core box). NOT MEASURED: check:eager-locale-catalogues, reason: PREREQUISITE NOT MET (needs a full console build for apps/console/dist/eager-closure.json). NOT MEASURED: check:readme-exports, reason: exit 1, but all 95 lines say 'type entry not on disk' for unbuilt packages, a prerequisite failure and not a finding.",
    "mcp_calls": "0 — no MCP tool used",
    "api_writes": "2 relay strokes, each a POST /repos/objectstack-ai/objectstack/dispatches from this seat: (1) pr_create, executed as POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos//issues/12225/assignees [os-warren]; (2) this os-dev-report comment, executed as POST /repos//issues/12201/comments. git push x3 (branch probe, two commits) is not a REST write. No label write, no PATCH.",
    "open_questions": [
    {
    "question": "When the org context renders in an app (WorkspaceSwitcher for multi-org users, CurrentOrganizationIndicator on single-org walled deployments), it still sits left of the app pill, so the bar's left edge is the org name. The ruling places the pill first but does not place the org context. Should it move?",
    "options": [
    "A: keep it where it is. Zero further change; the common single-org environment shows neither control, so the bar starts with the pill.",
    "B: move the org context to the right-hand cluster in app context only. It is a small AppHeader change, but the org context then sits in different places in app and platform contexts.",
    "C: move it into the avatar menu everywhere. That is a larger change with its own design decision."
    ],
    "recommendation": "A, until the maintainer's staging screenshots show a multi-org environment; it needs no new surface, and B or C is a design call the ruling did not make."
    }
    ],
    "out_of_scope_findings": [
    "carrier: none · noted, not filed — appTileColors repeats @object-ui/layout AppShell's private dark-mode lightness floor (at least 65 %, saturation eased above 80 %); consolidating means exporting the AppShell hex helpers or moving them into @object-ui/core, outside this claim",
    "carrier: none · noted, not filed — homeAffordancesFollowDeclaration-7256's AFFORDANCES source-scan table has no row for the switcher's new 「All apps」 entry; it is pinned behaviourally instead (AppSwitcher.appIdentity-12201 asserts the href is the declared home)",
    "carrier: none · noted, not filed — content/docs/guide/console-architecture.md's layout diagram still lists the app switcher under the sidebar; it was stale at BASE already"
    ],
    "gates": [
    {
    "command": "pnpm turbo run build --filter=@object-ui/app-shell^... --concurrency=2",
    "exit": 0,
    "verdict": "Tasks: 28 successful, 28 total; os-verify-lock: VERDICT command-exit 0"
    },
    {
    "command": "pnpm --filter @object-ui/app-shell type-check",
    "exit": 0,
    "verdict": "TYPECHECK_EXIT=0 (head c9ba7b8)"
    },
    {
    "command": "pnpm exec vitest run packages/app-shell/src/layout/ + 7256 + 5817 + 11674 pins",
    "exit": 0,
    "verdict": "Test Files 64 passed (64); Tests 462 passed (462)"
    },
    {
    "command": "pnpm exec vitest run packages/i18n/",
    "exit": 0,
    "verdict": "Test Files 83 passed (83); Tests 1321 passed | 13 skipped"
    },
    {
    "command": "pnpm --filter @object-ui/i18n type-check",
    "exit": 0,
    "verdict": "exit 0"
    },
    {
    "command": "pnpm --filter @object-ui/app-shell lint && pnpm --filter @object-ui/i18n lint",
    "exit": 0,
    "verdict": "os-verify-lock: VERDICT command-exit 0; 0 errors"
    },
    {
    "command": "pnpm check:i18n-keys",
    "exit": 0,
    "verdict": "Every in-scope call-site key resolves against the en pack (3358 keys) ..."
    },
    {
    "command": "pnpm check:i18n-drift",
    "exit": 0,
    "verdict": "0 en value(s) changed (3 key(s) added, 0 removed)"
    },
    {
    "command": "pnpm check:i18n-dead-keys",
    "exit": 0,
    "verdict": "report-only; none of the 3 new keys listed"
    },
    {
    "command": "pnpm check:control-bytes",
    "exit": 0,
    "verdict": "check-control-bytes: OK (scanned 8461 tracked text file(s))"
    },
    {
    "command": "pnpm check:new-line-citations",
    "exit": 0,
    "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s)"
    },
    {
    "command": "node scripts/check-changeset-no-major.mjs",
    "exit": 0,
    "verdict": "No changeset declares a major bump."
    },
    {
    "command": "node scripts/check-changeset-presence.mjs",
    "exit": 0,
    "verdict": "20 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)"
    },
    {
    "command": "pnpm check:vi-mock-specifiers / vi-mock-inherit / vi-mock-override-shape",
    "exit": 0,
    "verdict": "OK x3"
    },
    {
    "command": "pnpm check:test-path-roots / unreferenced-sources / phantom-deps / icon-record-names",
    "exit": 0,
    "verdict": "OK x4"
    },
    {
    "command": "pnpm check:changeset-claims / pending-changeset-literals",
    "exit": 0,
    "verdict": "pass; one pending changeset (11806) names packages/app-shell/README.md, and its sign-up-table paragraph is untouched by this diff"
    },
    {
    "command": "pnpm check:eager-locale-catalogues",
    "exit": 2,
    "verdict": "NOT MEASURED: PREREQUISITE NOT MET (no console build)"
    },
    {
    "command": "pnpm check:readme-exports",
    "exit": 1,
    "verdict": "NOT MEASURED: 95/95 lines say 'type entry not on disk' (unbuilt packages)"
    }
    ],
    "line_budget": "n/a",
    "deviations": [
    "File surface addition: content/docs/guide/console-architecture.md, content/docs/guide/console.md and packages/app-shell/README.md describe exactly the UI this card moves (the sidebar logo header and the Design in Studio entry), and AGENTS.md rule 2 makes docs part of done. These edits are declared in the PR body. Nothing under app-shell/src/environment/ or app-shell/src/console/home/ was touched, and nothing in objectstack.",
    "Interpretation, item 3: the phone drawer header keeps a trailing 「All apps」 icon link to the declared home beside the app's glyph and name, so a phone keeps its only way out of an app (the old Home row's job).",
    "Interpretation, item 5: the PREVIEW chip moves right only in app context; on platform surfaces (Home, orgs, Studio front door) it stays beside the mark it belongs to.",
    "Interpretation, item 6: 「left edge of the right-hand utility cluster」 is read as the first item of the bell/AI/help group, right after the search box; the label shows from lg (1024 px), and below that it is the pencil alone with a native title tooltip.",
    "Measured, no change: Studio is never listed as an app because a stock boot registers no studio app (per the @objectstack/studio package header), so no client-side filter was added.",
    "Browser screenshots were not captured (see tests); the PR body says so."
    ],
    "files_changed": [
    ".changeset/12201-app-identity-top-bar.md",
    "content/docs/guide/console-architecture.md",
    "content/docs/guide/console.md",
    "packages/app-shell/README.md",
    "packages/app-shell/src/layout/AppHeader.tsx",
    "packages/app-shell/src/layout/AppMark.tsx",
    "packages/app-shell/src/layout/AppSwitcher.tsx",
    "packages/app-shell/src/layout/UnifiedSidebar.tsx",
    "packages/app-shell/src/layout/appTileColors.ts",
    "packages/app-shell/src/layout/tests/AppHeader.appIdentity-12201.test.tsx",
    "packages/app-shell/src/layout/tests/AppSwitcher.appIdentity-12201.test.tsx",
    "packages/app-shell/src/layout/tests/AppSwitcher.publishState.test.tsx",
    "packages/app-shell/src/layout/tests/ConsoleLayout.appBrandingLogo-10827.test.tsx",
    "packages/app-shell/src/layout/tests/UnifiedSidebar.mobileAppHeader-12201.test.tsx",
    "packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts"
    ],
    "i18n_keys": {
    "added": [
    "topbar.editApp",
    "layout.appSwitcher.allApps",
    "layout.appSwitcher.editAppInStudio"
    ],
    "removed": []
    },
    "public_surface": {
    "@object-ui/app-shell": "AppSwitcher gains an optional prop designInStudioPath?: string | null (additive), and it now renders router Links, so it needs a Router context. AppHeader and UnifiedSidebar have no prop change and only the markup changes described above. AppMark and appTileColors are internal and not exported. No export was added or removed.",
    "@object-ui/i18n": "3 keys added to all ten packs; none removed; no export change"
    }
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    ACCEPT: PR objectui#12225 (head c9ba7b8) · domain:ui seat 2 · session_01G5TSaEwbEQsKMjhzTB4rEd · 2026-10-12T10:44Z

    Reviewed against GitHub and the diff, not the report. Claim 6121008577; report 6122271226; contract review 6122684858 on the PR (CONTRACT_REVIEW_TIER, this head, PASS).

    • Shape: draft on main. The first line is Fixes #12201, and no other closing keyword is in the body. Clause-②: yes. 24 files, 1,261 changed lines; check-governed-merges --pr reads NOT governed.
    • Ruling items 1–6: each is checked against the diff in the contract review's ①.8. The seat's own read agrees: one asset at 22/22/26 px; the pill and every row draw a glyph; the sidebar header is gone; the platform mark is gone in app context; the PREVIEW chip is beside the search box; and 「Edit app」 plus the dropdown's Studio row share one gate and one target.
    • Surface amended at ACCEPT: content/docs/guide/console-architecture.md, content/docs/guide/console.md and packages/app-shell/README.md. They describe exactly the moved UI, and the PR body declares them. Each changed sentence was read against the diff.
    • Changeset (@object-ui/app-shell and @object-ui/i18n minor): matches what the diff publishes. One sentence is missing: AppSwitcher now needs a Router context. The PR body says so; the changeset does not. The contract review judged that gap non-blocking (①.2), and the seat accepts it.
    • Open question: where the org context sits in app context stays as it is (A). The ruling did not place it, and a single-org environment shows neither control. If a multi-org environment is in scope, this goes to the maintainer as its own question.
    • NOT MEASURED, declared: the browser screenshots (acceptance 1–4, 6). The maintainer's staging screenshots after the pin move are the visual check. CI on this head reads 40 success and 3 skipped.
    • Serial relay to objectui#12198: AppHeader.tsx blocks were edited in place; nothing was extracted or renamed. The breadcrumb code, extraSegments with its routeType === 'page' branch, is untouched and in its old place. The console breadcrumb on a page route adds a 「页面」/Pages crumb, a metadata-type word on a user page; and pin that a Cloud owner or member sees neither the Studio pencil nor the hammer (cloud#2777 item 4) #12198 starts from this card's merge.
    • Landing: ready, then auto-merge, through the merge queue.

    Generated by Claude Code

  7. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    Contributor

    Landed · domain:ui seat 2 · session_01G5TSaEwbEQsKMjhzTB4rEd · 2026-10-12T11:05Z

    PR objectui#12225 merged through the merge queue as 38bb373 on main. Verified by content on origin/main, not by sha:

    • packages/app-shell/src/layout/AppMark.tsx is present.
    • AppSwitcher.tsx carries the 「All apps」 row (app-switcher-all-apps).
    • UnifiedSidebar.tsx no longer draws the appLogo header (0 hits).
    • The zh pack carries editApp (control: setUpProduction hits in the same file).

    pm:dispatched is removed in this same act; the card was closed by the PR's Fixes line. Follow-ups:


    Generated by Claude Code

  8. added a commit that references this issue on Oct 28, 2026
    38bb373
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p1

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions