What happens
DesktopAppSection.tsx:122 hardcodes the agent id:
<span className="desktop-app-icon"><AgentIcon agentId="codex" size={20} /></span>
That component renders both desktop Agents. There are two (internal/desktopapp/registry.go:36-62): ChatGPT Desktop, whose ProfileAgentID genuinely is codex, and WorkBuddy, which is a separate product from a different vendor. WorkBuddy's card therefore displays OpenAI's Codex logo.
This is worse than a missing icon. It is not a blank square the user reads as "unstyled" — it is a specific vendor's registered mark placed on a different vendor's product, in a shipped desktop app. frontend/src/components/icons/agents.tsx:9-13 already treats mark attribution as a compliance surface, and NOTICE is named as a release precondition in docs/distribution-compliance-policy.md.
Why it wasn't caught
AgentIcon has a fallback for exactly this case — an unknown id renders a generic Lucide Bot with data-mark-kind="fallback" (agents.tsx:130-144). Passing a literal "codex" bypasses it, so the code path designed to handle "no mark assigned yet" never runs.
Fix
Pass the real id. DesktopAgentStatus already carries id, so the change is agentId={desktopApp.id} — WorkBuddy then falls through to the generic Bot mark, which is correct and attributable today, with no new asset and no NOTICE change.
Two follow-ups that are separate decisions:
- A real WorkBuddy mark. Would need the same auditable basis the other five have: source URL, licence text, copyright holder, SHA-256, recorded in
asset-rights.json. Worth doing only if such a basis exists; the generic mark is the correct answer until it does.
DesktopAgentSelectionPage.tsx:68 uses a bare AppWindow for every desktop Agent, so the selection page and the card show different symbols for the same product. Unifying them is cosmetic but should follow whatever this issue settles on.
Suggested guard
agents.test.tsx already asserts mark provenance per Agent. A test that renders DesktopAppSection for each entry in desktopapp.Definitions() and asserts the rendered mark is not another Agent's asset would keep the next desktop Agent from inheriting the same bug.
What happens
DesktopAppSection.tsx:122hardcodes the agent id:That component renders both desktop Agents. There are two (
internal/desktopapp/registry.go:36-62): ChatGPT Desktop, whoseProfileAgentIDgenuinely iscodex, and WorkBuddy, which is a separate product from a different vendor. WorkBuddy's card therefore displays OpenAI's Codex logo.This is worse than a missing icon. It is not a blank square the user reads as "unstyled" — it is a specific vendor's registered mark placed on a different vendor's product, in a shipped desktop app.
frontend/src/components/icons/agents.tsx:9-13already treats mark attribution as a compliance surface, andNOTICEis named as a release precondition indocs/distribution-compliance-policy.md.Why it wasn't caught
AgentIconhas a fallback for exactly this case — an unknown id renders a generic LucideBotwithdata-mark-kind="fallback"(agents.tsx:130-144). Passing a literal"codex"bypasses it, so the code path designed to handle "no mark assigned yet" never runs.Fix
Pass the real id.
DesktopAgentStatusalready carriesid, so the change isagentId={desktopApp.id}— WorkBuddy then falls through to the genericBotmark, which is correct and attributable today, with no new asset and noNOTICEchange.Two follow-ups that are separate decisions:
asset-rights.json. Worth doing only if such a basis exists; the generic mark is the correct answer until it does.DesktopAgentSelectionPage.tsx:68uses a bareAppWindowfor every desktop Agent, so the selection page and the card show different symbols for the same product. Unifying them is cosmetic but should follow whatever this issue settles on.Suggested guard
agents.test.tsxalready asserts mark provenance per Agent. A test that rendersDesktopAppSectionfor each entry indesktopapp.Definitions()and asserts the rendered mark is not another Agent's asset would keep the next desktop Agent from inheriting the same bug.