Started: 2026-04-11
Worktree: /home/xcjam/workspace/commonly-uiux
Branch: uiux/enhance-2026-04-11
Coordinator: Claude Opus 4.6 (1M)
Status: ✅ Round 1 complete — all 5 tracks delivered, typecheck + lint green, ready for commit & deploy.
Status legend: ⏳ pending · 🔨 in-progress · ✅ done · ❌ blocked · 🧪 needs review · 🎨 needs live smoke test
- Agent Hub (registry) UI/UX enhancement — ✅
- Marketplace UI/UX enhancement — ✅
- App Integration page UI/UX enhancement — ✅ (Social section reorganized; full category regroup deferred because
GlobalIntegrations.tsxonly holds X + Instagram + the global-model-policy card, not a list with categories — noted in code asTODO(ui)) - Skill Marketplace with ratings/comments — ✅
- Fix stale skill star counts + sync freshness — ✅
- Enriched content for agent messages (emoji, memes/images) — ✅
- PostgreSQL 30-day message retention — ✅
- Task board UI/UX polish — ✅
- OpenAI image endpoint wired for agent avatar generation — ✅ (code landed; runtime blocked on OPENAI_API_KEY in GCP SM — see Phase 2)
- Generate nice avatars for all team agents — 🔜 Phase 2 (script written, needs API key)
- Remove useless "debug runtime" section from agent hub — ✅
- Typing indicators for agents — ✅
- Clawhub integration: DEFERRED. Use GitHub API refresh of existing
awesome-agent-skills-index.jsoninstead. Smaller attack surface, tighter guardrail. - LiteLLM for image gen: BYPASS. Direct OpenAI client for
/v1/images/generations. - Meme storage: Reuse existing
/api/uploads/multer endpoint. - Retention default: 30 days, configurable via
PG_MESSAGE_RETENTION_DAYS. - Worktree strategy: Single shared worktree, non-overlapping file ownership per agent — worked perfectly. No merge conflicts.
- ✅ Removed Runtime Debug
<Accordion>(old L3030-3129) and collapsed its wrapper Box - ✅ Removed reset
useEffect(old L2328-2331) - ✅ Removed helpers
getInstalledDebugKey,fetchInstalledRuntimeDebug,handleToggleInstalledDebug,copyInstalledDebug(old L830-913) - ✅ Removed state
installedDebugExpanded,installedRuntimeDebug - ✅ Pruned imports:
Accordion,AccordionSummary,AccordionDetails,ExpandMoreIcon(RefreshIcon + CopyIcon kept — still used in Admin tab) - ✅ Polished Installed tab empty state with
SmartToyOutlinedIcon+ headline + "Browse Discover" link - ✅ Polished Discover tab header (subtitle + wider gap + flexShrink on chip)
- Delta:
AgentsHub.tsx5035 → 4884 lines (−151 net) - Files:
frontend/src/components/agents/AgentsHub.tsx
Task Board polish:
- ✅ Typography: column headers 0.7→0.75rem, letterSpacing 0.8→0.4; card IDs/chips 0.68→0.72rem; titles 0.8→0.9rem; meta rows 0.68/0.7→0.85rem
- ✅ Card padding 10×12 → 14×14; border-left 3→2px; hover translate+shadow
- ✅ Tooltip wraps truncated titles (3-line clamp)
- ✅ Unicode markers replaced:
⛔→<BlockIcon>,↳→<SubdirectoryArrowRightIcon>,🔒→<LockOutlineIcon> - ✅ Per-column empty states (dashed-border centered Box with
InboxOutlinedIcon) - ✅ Mobile drawer constrained:
min(420px, calc(100vw - 48px))
Typing Indicator:
- ✅
AgentTypingIndicatorlocal component with stacked overlapping 24px avatars + animated three-dot@keyframes typingDot - ✅ State
typingAgents+ ref-based 30s safety timers keyed onagentName:instanceId - ✅ Pod-change cleanup effect + socket subscribe/unsubscribe on
agent_typing_start/agent_typing_stop - ✅ Rendered between message list and composer; returns
nullwhen empty
Enriched Content:
-
✅
node-emoji@^2.1.3added tofrontend/package.json -
✅
emojifyPreserveCode(raw)splits on fenced+ inline`via regex, emojifies only prose segments (avoids corrupting code blocks). Applied atmessageType === 'text'render site only — MarkdownContent.tsx untouched, so posts/comments unaffected. -
✅
<GifBoxOutlinedIcon>IconButton in composer (between emoji picker and attach), hidden file input acceptsimage/gif,image/png,image/jpeg,image/webp, POSTs to/api/uploadswith field nameimage(verified viauploads.ts:38), injects\n\ninto composer on success,CircularProgressduring upload. -
Files:
frontend/src/components/ChatRoom.tsx,frontend/package.json
Skills sync:
- ✅
backend/services/skillsRefreshService.ts(new) — fetches upstream JSON fromraw.githubusercontent.com/openclaw/skills/main/..., overridable viaSKILLS_UPSTREAM_INDEX_URL, usesGITHUB_PATbearer auth, 100ms delay between unique-repo star count requests, preserves partial progress on 401/rate-limit, keeps stale local file on upstream failure (never blanks). StampsupstreamRefreshedAt+localRefreshedAt. ExportsgetLastRefreshAt(). - ✅
backend/services/skillsCatalogService.ts— mtime-based cache invalidation +invalidateCache()+getLastRefreshedAt()exports - ✅
backend/services/schedulerService.ts— 6-hourly cron0 */6 * * *+ 30s startup kick - ✅
backend/routes/skills.ts/catalogresponse extended with refreshedAt timestamps
Skill ratings:
- ✅
backend/models/SkillRating.ts(new) —skillId + userIdcompound unique, rating 1-5, comment ≤2000,getAggregated()+getAggregatedMany()statics - ✅ Routes in
backend/routes/skills.ts:POST /:skillId/rating(upsert),GET /:skillId/ratings(paginated),GET /:skillId/ratings/summary,DELETE /:skillId/rating,GET /ratings/summary?skillIds=a,b,c(batch) - ✅
frontend/src/components/skills/SkillsCatalogPage.tsx—<Rating>on each card, detail<Dialog>with summary (avg + histogram bars), interactive rating form, comments list, "Highest rated" sort option, "Last updated X ago" indicator, manual refresh button
Apps Marketplace polish:
- ✅ Hero section with gradient background, h3 headline, inline pill-shaped search, pod select, "Submit App" button
- ✅ Featured section converted to horizontal scroll strip with scroll-snap
- ✅
AppCard.tsx— avatar 56→64px, stronger hover, absolute-positioned category chip top-right, "Installed" chip bottom-right
Admin Integrations polish:
-
✅ "Social" section header above X/Instagram cards
-
✅ X + Instagram edit forms wrapped in collapsed-by-default
<Accordion> -
🔜 Full Chat/Email/Other category grouping deferred (requires data-fetch refactor; noted as
TODO(ui)in file) -
Files:
backend/services/skillsRefreshService.ts(new),backend/models/SkillRating.ts(new),backend/services/skillsCatalogService.ts,backend/services/schedulerService.ts,backend/routes/skills.ts,frontend/src/components/skills/SkillsCatalogPage.tsx,frontend/src/components/apps/AppsMarketplacePage.tsx,frontend/src/components/apps/AppCard.tsx,frontend/src/components/admin/GlobalIntegrations.tsx
-
✅
openai@^4.77.0added tobackend/package.json(installed @ 4.104.0) -
✅
backend/services/openaiImageService.ts(new) — lazy client init,gpt-image-1→dall-e-3fallback, rate-limit + 5xx retry-once, typedOpenAIImageErrorkinds, cost-estimate logging,b64_json→ URL-fetch conversion, CJS compat footer -
✅
backend/services/agentAvatarService.ts— three-tier provider chain OpenAI → Gemini → SVG; env toggleAVATAR_PROVIDER=openai|gemini|auto; existing Gemini code untouched (purely additive) -
✅
backend/models/User.ts—avatarMetadataextended withsource: 'openai'|'gemini'|'svg'|'manual'+model: string -
✅
k8s/helm/commonly/templates/secrets/api-keys.yaml—OPENAI_API_KEYmapping already present (no YAML edit needed) -
✅
backend/scripts/generate-team-avatars.ts(new) — idempotent, TEAM array of liz/theo/nova/pixel/ops/x-curator with personality-matched prompts, resolves viaAgentIdentityService.getOrCreateAgentUser, writes toUser.profilePicture+avatarMetadata,--forceflag, cost total -
✅
docs/AGENT_AVATARS.md(new) — GCP SM setup, ESO force-sync, script usage, cost table, adding new agents -
Files:
backend/package.json,backend/services/openaiImageService.ts(new),backend/services/agentAvatarService.ts,backend/models/User.ts,backend/scripts/generate-team-avatars.ts(new),docs/AGENT_AVATARS.md(new)
Typing events:
- ✅
backend/services/agentTypingService.ts(new) —bindSocketIO,emitAgentTypingStart,emitAgentTypingStop, 60s safety timer keyed onpodId:agentName:instanceId, structuralSocketIOLikeinterface, CJS compat footer - ✅
backend/server.ts— binds socket.io near other one-time socket setup; client-sideagent_typing_start/agent_typing_stopforwarders insideio.on('connection')that re-broadcast intopod_{podId}room - ✅
backend/services/agentEventService.ts— lazygetTypingService()+TYPING_EVENT_TYPESallowlist (heartbeat,chat.mention,summary.request,discord.summary,integration.summary,ensemble.turn); fire-and-forgetsignalAgentTyping(event)insideenqueue()after websocket push - ✅
backend/services/agentMessageService.ts— emitsagent_typing_stopat the entry ofpostMessage()wrapped in try/catch so every return path (skip/dedupe/error/success) clears the indicator
PG retention:
-
✅
backend/services/pgRetentionService.ts(new) — daily cron0 3 * * *UTC, readsPG_MESSAGE_RETENTION_DAYS(default 30), idempotent init guard, swallows errors so cron keeps running, gated onNODE_ENV !== 'test' -
✅
backend/models/pg/Message.ts—static async deleteOlderThan(days)withNOW() - $1::interval RETURNING id, validates days > 0, returns{ deleted: N } -
✅
backend/server.ts— callsinitPgRetention()after PG success log -
Files:
backend/services/agentTypingService.ts(new),backend/services/pgRetentionService.ts(new),backend/server.ts,backend/services/agentEventService.ts,backend/services/agentMessageService.ts,backend/models/pg/Message.ts
- Review diffs from each agent — 17 modified + 7 new files, no track overlaps
-
cd backend && npm install openai@^4.77.0— installed @ 4.104.0 -
cd frontend && npm install node-emoji@^2.1.3— installed @ 2.2.0 -
backend && npm run tsc:check— clean -
frontend && npm run typecheck— clean -
backend && npm run lint— 865 errors ALL pre-existing (main branch baseline matches;eslint . --ext .jsdoesn't cover my.tschanges anyway) -
frontend && npm run lint— 104 pre-existing JSX-extension warnings from Apr 8.tsxmigration + 1 pre-existing unescaped-entity error inPersonalityBuilder.tsx(untouched by this work) - Zero new lint errors introduced by Round 1
- Commit tracks as coherent chunks
- Report to user
- Generate actual avatars for team agents: blocked on
OPENAI_API_KEYin GCP Secret Manager. Commands indocs/AGENT_AVATARS.md. Once key lands:npx ts-node backend/scripts/generate-team-avatars.ts→ images flow intoUser.profilePicture. - Deploy to dev: local docker build backend + frontend + gateway, bump
values-dev.yamltags, helm upgrade with all 3-fflags (per memory: includevalues-private.yaml). Restart-safe: no breaking schema changes, no API removals. - MCP Playwright smoke test: navigate
app-dev.commonly.me/agents,/skills,/apps,/pods/<id>— confirm (a) no runtime debug accordion, (b) skills page shows ratings, (c) apps hero renders, (d) agent hub discover polish, (e) chat room empty state + typing indicator wire (no server-side stimulus yet). - GCP SM backfill: create
commonly-dev-openai-api-key+ force ESO sync + roll backend.