← All proposals

Agent avatar

Start from the PDS v2 Avatar (src/components/identity/Avatar, branch v2.x), renamed AgentAvatar (class pds-agent-avatar).

Net-new componentOpen in Storybook

proposals/AgentAvatar/HANDOFF.md78 lines · View on GitHub

Handoff: AgentAvatar

What and why

People and agents show up side by side in activity logs, comment threads and lists. A user has to know at a glance when an agent did something, and the PDS Avatar looks like a person. This proposal is a purpose-built agent avatar: a dark disc with a lightning bolt, ringed by the AI gradient. The ring is the first cue and the bolt is the second, so the signal never relies on color alone, and a required screen-reader label says it is an agent.

It started from the PDS v2 Avatar and keeps only its sizes, link behavior and a11y. The image, per-user color and user fallback are removed.

  • Figma: Agent Avatar page in PDS-Proposals (6 stories, light and dark, flat captures; sent 2026-10-16). Jira: none. Source was Erika's brief and a reference screenshot.
  • Context: context.md

Exploration and decisions

  • A separate component, not an Avatar variant. One shared look for all agents. Per-agent identity is the name shown next to it.
  • The ring is stacked backgrounds. --pds-gradient-ai-active is a gradient, so it cannot go in border-color. The fill sits on the content-box, a surface-colored gap on the padding-box and the gradient on the border-box.
  • Fill and icon use the foreground tokens (--pds-color-foreground-default and -reverse). Both flip in dark mode, so it becomes a light disc with a dark bolt.
  • hasHalo (default true). Off leaves the disc and bolt at the same overall size; the icon is not enlarged.
  • shape (circle default, square) was added back on request after the non-agentic options were removed.
  • iconName: zappy for Pantheon agents, sparklesSolid for third-party agents.

API

Prop Type Default Purpose
ariaLabel string none Accessible name when used as a link. Falls back to label.
className string none Additional class names.
hasHalo boolean true Show the AI-gradient ring around the avatar.
iconName 'sparklesSolid' | 'zappy' 'zappy' Icon inside the avatar.
label string required Screen-reader text that says this is an agent. Pass it translated.
linkContent ReactNode none A link element from the router of your choice.
shape 'circle' | 'square' 'circle' Avatar shape.
size 'xs' | 's' | 'm' | 'l' | 'xl' 's' 16px, 20px, 24px, 32px, 40px.

Variants and states: circle and square; halo on and off; the five sizes; as a link (hover and focus-visible).

Tokens used

  • --pds-border-radius-default
  • --pds-border-width-outline
  • --pds-color-foreground-default
  • --pds-color-foreground-reverse
  • --pds-color-interactive-focus
  • --pds-color-surface-default
  • --pds-gradient-ai-active

Impact

impact.md finds nothing that reaches existing PDS components: everything is scoped to pds-agent-avatar. It does not list the proposals that build on this one, though: AvatarLabel and IdentityBlock render it, and Spinner's hasAvatar uses it. Port it first.

Reused vs net-new

  • Reused: PDS Icon (through the local wrapper, for sparklesSolid), design tokens, the v2 Avatar structure and link behavior.
  • Net-new: the whole component. See custom.md (class pds-agent-avatar, five --avatar-* variables, no raw values).

Accessibility

  • The avatar is decorative to the eye and named for screen readers: label renders as visually-hidden text, and the icon is aria-hidden.
  • As a link, the link's aria-label is ariaLabel, falling back to label. Focus-visible uses --pds-color-interactive-focus.
  • The agent signal is the ring and the bolt together, so it does not rely on color alone.
  • The a11y panel has not been run on these stories. Run it in light and dark before the port.

Decisions and open questions

  • Confirm in the browser that the 1px ring and gap read at xs (2x), and that the dark-mode inversion (light disc, dark bolt) is wanted.
  • Should the icon grow when hasHalo is off?
  • No white-on-gradient token exists; the fill and icon use the foreground tokens.
  • sparklesSolid is a local icon added by the Icon proposal (see ../Icon/). Port that with this; the Icon proposal is ready (../Icon/HANDOFF.md).

Port notes

  • Goes in src/components/identity/AgentAvatar in pds-toolkit-react, next to Avatar. Create it with npm run generate:component, then copy the files over.
  • Swap the local mergeClasses for the real one, and the local Icon wrapper for the package Icon once sparklesSolid exists there.
  • Known gaps against v2 conventions: none beyond the above.

Preview

npm run storybook, then Identity/Agent Avatar.