fabro/docs/superpowers/plans
Bryan Helmkamp d17599898e
feat(web): show creator avatar on run "Created by" cell (#319)
## Summary

The run Overview tab's "Created by" cell rendered every user as a
colored circle with the first letter of their login. Reviewers and run
owners expected the same GitHub avatar shown on `/profile` and in the
top-right nav. The cell only had `login` to work with — the
`PrincipalUser` schema carried no avatar URL.

This threads an optional `avatar_url` through `UserPrincipal`
end-to-end: schema, server auth, and frontend. The avatar is captured at
action time from the request's auth context and persisted with the run's
`created_by` principal — a point-in-time snapshot, the same pattern as
audit logs and chat apps.

## What changed

- **`fabro-types`** — `UserPrincipal` gains `avatar_url: Option<String>`
with `#[serde(default, skip_serializing_if)]`, plus a
`Principal::user_with_avatar` constructor. The existing
`Principal::user` constructor is unchanged (sets `None`), so test
fixtures and CLI/replay call sites need no edits.
- **OpenAPI** — `PrincipalUser` gains an optional nullable `avatar_url`;
Rust (progenitor) and TypeScript clients regenerated.
- **`fabro-server`** — `auth_context_from_session` (cookie auth) and
`classify_user_token` (JWT auth) populate the principal's avatar from
the session/JWT, treating an empty string as `None`.
- **`fabro-web`** — the `run-summary-panel` "Created by" cell renders an
`<img>` when `avatar_url` is present, falling back to the initial circle
otherwise.

## Compatibility

The field is optional with serde defaults, so old persisted runs and
`RunEvent.actor` payloads deserialize unchanged — they show the
initial-circle fallback. No migration or backfill.

## Known gap

CLI-initiated runs (`fabro run ...`) still show the initial circle: the
CLI auth flow hardcodes an empty `avatar_url` in the JWT subject
(`cli_flow.rs:508`). Wiring the avatar through CLI login
(`~/.fabro/auth.json`, JWT claims, refresh-token chain) is a deliberate
follow-up. Web-initiated runs get the avatar today.

## Test plan

- `cargo nextest run --workspace` — 5,832 tests pass, including new
`principal.rs` and `principal_round_trip.rs` cases covering avatar
serialization and legacy-JSON (no-field) deserialization.
- `cd apps/fabro-web && bun test run-summary-panel` — 13 tests pass,
including a new case asserting the `<img>` renders with the avatar src.
- `bun run typecheck`, `cargo +nightly-2026-04-14 fmt --check --all`,
and `clippy --workspace --all-targets -- -D warnings` all clean.
- Manual: restart `fabro server`, create a run from the web UI, confirm
the real avatar renders on the Overview tab; confirm an older run falls
back to the initial circle.

---

[![Compound Engineering
v2.60.0](https://img.shields.io/badge/Compound_Engineering-v2.60.0-6366f1)](https://github.com/EveryInc/compound-engineering-plugin)
🤖 Generated with Claude Opus 4.7 (1M context, extended thinking) via
[Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 09:11:57 -04:00
..
2026-04-29-metadata-snapshot-events.md feat(workflow): emit metadata snapshot events 2026-04-29 19:31:13 -04:00
2026-04-30-duplicate-type-unification.md docs(plans): add command output streaming and type unification plans 2026-04-30 08:36:00 -04:00
2026-04-30-preserve-exec-failure-diagnostics.md fix(workflow): preserve exec failure diagnostics 2026-05-01 08:45:50 -04:00
2026-05-02-event-module-split.md refactor(workflow): split event module by responsibility 2026-05-02 14:52:10 -04:00
2026-05-02-server-readiness-timeouts.md fix(cli): bound server readiness probes 2026-05-02 20:13:18 -04:00
2026-05-02-settings-driven-llm-providers-models.md docs(llm): finish configurable provider cleanup (#260) 2026-05-13 17:17:54 -04:00
2026-05-04-cross-tab-sse-coordination.md chore: add plan 2026-05-04 16:09:12 -04:00
2026-05-04-model-test-bounded-concurrency.md chore: update plan 2026-05-04 12:55:19 -04:00
2026-05-04-unique-git-checkpoint-commit-message-path.md chore: add plan 2026-05-04 11:12:40 -04:00
2026-05-05-clean-pierre-virtualizer-integration.md chore: plan 2026-05-06 07:15:18 -04:00
2026-05-05-decouple-interrupts-from-steering.md Wire end-to-end steering for running agents (#209) 2026-05-05 15:34:16 -04:00
2026-05-06-cli-input-overrides.md feat(cli): support sparse input overrides (#222) 2026-05-09 10:00:35 -04:00
2026-05-06-improve-cli-api-error-display.md fix(cli): preserve API error details 2026-05-06 14:03:12 -04:00
2026-05-06-polished-foreground-tty-logging.md feat(cli): polish foreground TTY logs 2026-05-06 15:31:25 -04:00
2026-05-08-generated-typescript-api-client-migration.md feat(web): migrate to generated API client 2026-05-08 07:44:33 -07:00
2026-05-08-run-owned-sandbox-lifecycle.md chore: plan run-owned sandbox lifecycle 2026-05-08 14:45:56 -07:00
2026-05-09-daytona-run-terminal.md chore: plan 2026-05-09 19:02:03 -04:00
2026-05-09-fixed-project-workflow-directory.md fix(workflow): ignore deprecated project directory 2026-05-09 10:55:56 -04:00
2026-05-09-inline-markdown-run-titles.md chore: plans 2026-05-08 18:59:49 -07:00
2026-05-09-live-stage-token-projection.md feat(billing): project live stage token usage 2026-05-09 15:25:51 -04:00
2026-05-09-remove-local-worktree-mode.md refactor(workflow): remove local worktree mode 2026-05-09 11:04:23 -04:00
2026-05-09-run-files-diff-scope-picker.md feat(run-files): add sandbox diff scopes 2026-05-09 13:00:14 -04:00
2026-05-10-auth-sessions-backend.md feat(auth): add unified session API 2026-05-10 14:16:23 -04:00
2026-05-10-auth-sessions-frontend.md chore: plans 2026-05-10 23:40:02 -04:00
2026-05-10-live-events-page.md feat(web): build live events page in settings 2026-05-10 14:05:10 -04:00
2026-05-10-sandbox-services-backend.md feat(server): list sandbox services 2026-05-10 11:24:39 -04:00
2026-05-10-sandbox-services-frontend.md feat(web): add Services tab to sandbox page 2026-05-10 11:56:05 -04:00
2026-05-11-automations-end-to-end.md chore: plans 2026-05-10 23:40:02 -04:00
2026-05-13-path-based-daytona-dockerfiles.md feat(manifest): support path-based Daytona Dockerfiles (#258) 2026-05-13 12:32:15 -04:00
2026-05-13-sandbox-repo-layout-plan.md feat(sandbox): prepare clone layout for multi-repo runs (#250) 2026-05-14 09:38:20 -04:00
2026-05-14-optional-llm-install.md feat(install): make LLM setup optional in web installer and CLI (#265) 2026-05-14 22:34:39 -04:00
2026-05-15-sandbox-network-details.md feat(sandbox): surface provider links and network policy (#275) 2026-05-16 10:16:18 -04:00
2026-05-16-chats-new-fabro-web-port.md feat(fabro-web): port /chats/new + /chats/:id from prototype (#289) 2026-05-16 17:10:16 -04:00
2026-05-16-source-aware-template-diagnostics.md feat(template): add source-aware diagnostics (#292) 2026-05-16 18:47:37 -04:00
2026-05-16-static-workflow-structure-rendering.md feat(web): show creator avatar on run "Created by" cell (#319) 2026-05-20 09:11:57 -04:00
2026-05-17-live-provider-workflow-testing.md feat(web): show creator avatar on run "Created by" cell (#319) 2026-05-20 09:11:57 -04:00
2026-05-17-provider-adapter-boundary-cleanup.md feat(web): show creator avatar on run "Created by" cell (#319) 2026-05-20 09:11:57 -04:00
2026-05-18-server-side-run-pairing-api-events.md feat(web): show creator avatar on run "Created by" cell (#319) 2026-05-20 09:11:57 -04:00
2026-05-18-vault-and-credential-source-cleanup.md refactor(auth): split credential sources and vault schemas (#306) 2026-05-18 11:07:42 -04:00