Sub of #14598 (FM cockpit AgentCard) · Refs #14560 · Refs #14778 (the avatarUrl hoist, merged) · Refs #14774 (card -- null-avatar review watch-item)
Operator direction (2026-07-04): agent profile avatars already live on the agents' GitHub accounts, and the GitHub avatar endpoint serves smaller sizes. So the cockpit avatar can be derived automatically from each agent's githubUsername (which the DTO row already carries) -- no manual setAvatar needed for the common case.
Scope
In the fleet cockpit DTO (src/ai/fleet/fleetCockpitStatus.mjs), derive avatarUrl from githubUsername via the GitHub avatar endpoint (https://github.com/{username}.png?size=N, a small cockpit-appropriate size), keeping metadata.avatarUrl (setAvatar) as an explicit override:
avatarUrl: metadata.avatarUrl ?? githubAvatarUrl(githubUsername) ?? null
Contract Ledger
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback / Edge Case |
Docs |
Evidence |
src/ai/fleet/fleetCockpitStatus.mjs row avatarUrl |
Operator direction captured in this ticket; existing #14778 avatarUrl DTO field; existing githubUsername in the fleet roster DTO |
When metadata.avatarUrl exists, use it as the explicit override. Otherwise, derive a sized GitHub avatar URL from githubUsername: https://github.com/{username}.png?size=80. |
If no explicit avatar and no githubUsername, return null rather than undefined or a malformed URL. |
JSDoc/summary in the helper is sufficient; no public guide surface. |
npm run test-unit -- test/playwright/unit/ai/services/fleet/fleetCockpitStatus.spec.mjs; hosted unit + integration checks. |
test/playwright/unit/ai/services/fleet/fleetCockpitStatus.spec.mjs avatar contract |
Same ticket + DTO contract above |
Cover all three paths: explicit override wins, username-only derives the GitHub URL with size=80, username-less agent surfaces null. |
Test remains local to the DTO unit suite; no overlays or mutable config templates involved. |
Focused DTO unit spec and hosted CI. |
|
Resolves the null-avatar polish
This dissolves the null-avatarUrl watch-item from #14774's review (Ada + GPT): every agent with a githubUsername (the common case) now surfaces a real GitHub avatar, so the card renders the crafted avatar instead of a broken-image glyph. null remains only for a username-less agent.
Acceptance Criteria
Filed by Vega (@neo-opus-vega · Claude Opus 4.8).
Sub of #14598 (FM cockpit AgentCard) · Refs #14560 · Refs #14778 (the
avatarUrlhoist, merged) · Refs #14774 (card -- null-avatar review watch-item)Operator direction (2026-07-04): agent profile avatars already live on the agents' GitHub accounts, and the GitHub avatar endpoint serves smaller sizes. So the cockpit avatar can be derived automatically from each agent's
githubUsername(which the DTO row already carries) -- no manualsetAvatarneeded for the common case.Scope
In the fleet cockpit DTO (
src/ai/fleet/fleetCockpitStatus.mjs), deriveavatarUrlfromgithubUsernamevia the GitHub avatar endpoint (https://github.com/{username}.png?size=N, a small cockpit-appropriate size), keepingmetadata.avatarUrl(setAvatar) as an explicit override:avatarUrl: metadata.avatarUrl ?? githubAvatarUrl(githubUsername) ?? nullContract Ledger
src/ai/fleet/fleetCockpitStatus.mjsrowavatarUrlavatarUrlDTO field; existinggithubUsernamein the fleet roster DTOmetadata.avatarUrlexists, use it as the explicit override. Otherwise, derive a sized GitHub avatar URL fromgithubUsername:https://github.com/{username}.png?size=80.githubUsername, returnnullrather thanundefinedor a malformed URL.npm run test-unit -- test/playwright/unit/ai/services/fleet/fleetCockpitStatus.spec.mjs; hosted unit + integration checks.test/playwright/unit/ai/services/fleet/fleetCockpitStatus.spec.mjsavatar contractsize=80, username-less agent surfacesnull.Resolves the null-avatar polish
This dissolves the null-
avatarUrlwatch-item from #14774's review (Ada + GPT): every agent with agithubUsername(the common case) now surfaces a real GitHub avatar, so the card renders the crafted avatar instead of a broken-image glyph.nullremains only for a username-less agent.Acceptance Criteria
avatarUrlfromgithubUsername(a sized GitHub avatar URL) when there is no explicitmetadata.avatarUrl.metadata.avatarUrl(setAvatar) still wins (override path).null(no crash, no malformed URL).Filed by Vega (@neo-opus-vega · Claude Opus 4.8).