Skip to content

Redesign the bot web pages with BotKit's own design language#36

Merged
dahlia merged 27 commits into
fedify-dev:mainfrom
dahlia:design/profile-pages
Jul 7, 2026
Merged

Redesign the bot web pages with BotKit's own design language#36
dahlia merged 27 commits into
fedify-dev:mainfrom
dahlia:design/profile-pages

Conversation

@dahlia

@dahlia dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member

This replaces the Pico CSS–based profile pages with a design system of BotKit's own. The pages a bot serves—its profile, individual posts, follower list, and the multi-bot instance index—now use a quiet, self-hosted design that foregrounds each bot's identity, and the whole brand and design language is written up in DESIGN.md.

Why

The old pages loaded Pico CSS from a third-party CDN, had no identity of their own, and made a bot's public face depend on a network fetch to someone else's server. But the deeper problem was not the stylesheet; it was the question of ownership. A user's bot profile belongs to that bot and to the person who built it, not to BotKit. A framework that stamps its own brand onto every page it generates makes each of its users' creations look like a demo of the framework rather than a thing its author made. The design language should do the opposite and let people's bots feel like theirs.

That single question—whose page is this?—is the backbone of the whole system, and it produces two modes. Canvas mode is what BotKit uses when it hosts someone else's bot: restrained, neutral chrome driven by the bot's own accent color, with BotKit appearing only as a small footer credit. Expression mode is BotKit speaking as itself, with a confident identity, and it is reserved for BotKit's own surfaces such as the project homepage and docs; it is documented but deliberately not shipped by the library or applied to a hosted bot's pages. Every page the library serves is Canvas mode. Making this distinction explicit is what keeps future work from quietly turning users' pages back into framework advertising.

Bundling the stylesheet and fonts locally rather than pulling them from a CDN follows from the same reasoning and from a practical constraint. A bot's appearance should not break because a CDN is slow, blocked, or gone, and visitors should not be exposed to a third party just for loading a profile. And because BotKit is a library, its design has to arrive with no build step on the user's side: a bot author installs the package and gets the full front end, fonts included, on both Deno and Node.js, without configuring a bundler or running an asset pipeline of their own.

How it works

The Canvas-mode design system lives in src/css/botkit.css. It is built from a small set of semantic neutral tokens plus twenty accent presets, one per color name, whose values are lifted verbatim from Pico's own themes so each accent keeps its accessibility-tuned link and contrast colors in both light and dark schemes without re-deriving twenty palettes by hand. Color is only ever applied through those tokens, so restraint is the default: the accent shows up on links, the follow button, and the repost marker, and almost nothing else. The pages use a single quiet typeface (Inter), and dark scheme is handled by overriding the neutral tokens under both the operating-system prefers-color-scheme preference and an explicit data-theme attribute.

The page components in src/components/ and src/pages.tsx were rewritten around this system: a profile header with an overlapping avatar, posts as quiet cards with friendly timestamps, a native follow dialog, follower and bot rosters, and the footer credit. Reposts are now clearly distinguished from the bot's own writing—a post whose author differs from the profile's bot carries an explicit “Reposted” marker and shows the original author, following the familiar convention — so a boosted post is never mistaken for something the bot wrote.

The no-build-step promise is kept by a small codegen step rather than by shipping loose files. The authoring sources (src/css/botkit.css and the woff2 files in src/fonts/) are compiled by scripts/build-assets.ts, run through mise run generate:assets, into two committed modules: src/static/style.ts holds the minified stylesheet as a string, and src/static/fonts.ts holds the fonts as base64. Those generated modules are plain source, so they ship as-is to JSR and are bundled by tsdown for npm, and they load identically on both runtimes with no filesystem access and no path resolution. Embedding the assets as source is what makes the “no build step on either runtime” guarantee hold at once; the cost is roughly a hundred kilobytes of base64 in the package, which is a fair price for a framework whose look arrives out of the box. The authoring sources and the codegen script are excluded from the published package.

At runtime the assets are served from a content-addressed path (src/assets.ts, wired into the existing request handler in src/instance-impl.ts next to the custom-emoji route). The path segment is a fingerprint computed over the full stylesheet text and the actual font bytes, so it changes whenever any asset changes—even if a font's byte length stays the same—and only the current fingerprint is served, with Cache-Control: immutable. A request carrying a stale or mistyped fingerprint is rejected with a 404 rather than caching the current bytes under the wrong URL for a year, which keeps the content-addressed contract honest.

The public options are unchanged apart from one addition. pages.color (the twenty accent names, default green) and pages.css (custom CSS, now injected after BotKit's stylesheet so it can override any token) still work as before, and a new pages.theme option selects the color scheme ("auto", "light", or "dark"; default "auto"). Because the components read tokens rather than literal colors, a few lines of custom CSS overriding a variable can restyle the whole page coherently.

Finally, DESIGN.md documents the two modes, the tokens, the components, the theming API, and the asset pipeline, with rationale and code examples, and AGENTS.md points contributors to it before they touch the front end.

Testing and verification

The web-page behavior is covered by tests in pages.test.ts: the profile links the bundled stylesheet rather than a CDN, the theme name and scheme are reflected on the document, the asset routes serve the stylesheet and fonts with immutable caching, a stale fingerprint is rejected, and the CSS minifier preserves the descendant space before a pseudo-class so custom-emoji sizing keeps matching. mise run check and mise run test pass, the Node.js build bundles the generated asset modules, and the Node.js test suite passes against the built output. The pages were also verified in a real browser with Playwright across light and dark schemes, several accent colors, and mobile widths, including the repost indicator.

Summary by CodeRabbit

  • New Features

    • Bot pages now use a refreshed design with local styling, better light/dark support, and a new theme option (auto, light, dark).
    • Profile, follower, post, and multi-bot pages have improved layouts, clearer section headings, and updated buttons/icons.
  • Bug Fixes

    • Improved content safety when rendering posts.
    • Asset loading now uses bundled stylesheet and fonts with reliable caching, avoiding external dependencies.

Redesign the bot web pages with a self-contained, quiet "Canvas mode"
that foregrounds each bot's own identity, driven by the bot's accent
color. Bundle the stylesheet and Inter font locally (served from a
content-addressed, immutable path) so pages need no CDN and no build
step on Deno or Node.js. Add a pages.theme option, distinguish reposts
from the bot's own posts, and document the two-tier brand/design
language in DESIGN.md.

Assisted-by: Claude Code:claude-opus-4-8
@dahlia dahlia self-assigned this Jul 7, 2026
@dahlia dahlia added the enhancement New feature or request label Jul 7, 2026
@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

@codex review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dahlia, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 10 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 91557dd0-4d76-486c-8c22-e0f586bfcc7d

📥 Commits

Reviewing files that changed from the base of the PR and between 1a675ea and 2fedd51.

📒 Files selected for processing (12)
  • DESIGN.md
  • packages/botkit/package.json
  • packages/botkit/scripts/build-assets.ts
  • packages/botkit/src/assets.ts
  • packages/botkit/src/components/FollowButton.tsx
  • packages/botkit/src/components/Message.tsx
  • packages/botkit/src/css/botkit.css
  • packages/botkit/src/fonts/LICENSE-inter.txt
  • packages/botkit/src/message-impl.ts
  • packages/botkit/src/pages.tsx
  • packages/botkit/src/static/style.ts
  • packages/botkit/src/static/version.ts
📝 Walkthrough

Walkthrough

This PR introduces BotKit's self-contained design language for web pages, replacing Pico CSS. It adds a build script and asset-serving module for bundled/fingerprinted CSS and fonts, rewrites Layout/FollowButton/Follower/Message/pages components with bk- namespaced markup, adds a PagesOptions.theme option, and documents the design system in DESIGN.md.

Changes

BotKit design language and asset pipeline

Layer / File(s) Summary
Asset generation and serving
packages/botkit/scripts/build-assets.ts, packages/botkit/src/static/*.ts, packages/botkit/src/assets.ts, packages/botkit/src/instance-impl.ts, packages/botkit/src/bot.ts, mise.toml, packages/botkit/deno.json, packages/botkit/package.json, packages/botkit/src/fonts/LICENSE-inter.txt
Adds a Deno script generating minified CSS and base64-embedded fonts into static modules, an assets.ts module computing a fingerprint (ASSET_VERSION) and serving /.botkit/<version>/... requests, wiring into InstanceImpl.fetch(), a new PagesOptions.theme field, and build/packaging config updates.
Stylesheet design tokens
packages/botkit/src/css/botkit.css
Adds the full source stylesheet defining color/typography/spacing tokens, accent presets, dark-mode overrides, and component styles (profile, buttons, feed, prose, roster, dialog, footer, responsive).
Component rewrites
packages/botkit/src/components/Layout.tsx, FollowButton.tsx, Follower.tsx, Message.tsx, Message.test.tsx, message-impl.ts
Rewrites components to use hono/jsx and bk- classes, adds BotKitCredit/CopyIcon/FeedIcon, reworks follow dialog and message/attachment rendering with sanitized HTML, and exports htmlXss.
Page templates and tests
packages/botkit/src/pages.tsx, packages/botkit/src/pages.test.ts
Adds a PageHeading component and rewrites profile/followers/hashtag/message/multi-bot pages with bk- markup; adds tests for asset serving and XSS sanitization.
Design documentation
DESIGN.md, AGENTS.md, CHANGES.md, docs/concepts/bot.md
Documents Canvas/Expression modes, theming API, asset pipeline, and updates changelog/agent guidance/docs for the new theme option.

Estimated code review effort: 4 (Complex) | ~75 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant InstanceImpl
  participant serveAsset as assets.ts
  participant StaticModules as style.ts/fonts.ts

  Client->>InstanceImpl: GET /.botkit/{version}/botkit.css
  InstanceImpl->>serveAsset: serveAsset(pathname)
  serveAsset->>StaticModules: read embedded css/font bytes
  StaticModules-->>serveAsset: css string / font bytes
  serveAsset-->>InstanceImpl: Response(css, immutable cache, ETag) or 404
  InstanceImpl-->>Client: rendered response
Loading

Possibly related PRs

  • fedify-dev/botkit#24: Both PRs modify the same rendering/routing components (pages.tsx, Layout.tsx, FollowButton.tsx), touching multi-bot page routing and layout.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: redesigning BotKit’s bot web pages with its own design language.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces Pico CSS with a custom, self-contained design language ('Canvas mode') for BotKit's web pages, bundling fonts and stylesheets locally to eliminate external CDN dependencies. It introduces an asset-generation pipeline to compile these assets into static TypeScript modules and serves them with content-hashed paths for immutable caching. Feedback on the changes highlights a potential runtime TypeError in Follower.tsx due to a premature function call on a potentially null author, an incorrect type check on a URL object in pages.tsx, a missing unique key in a JSX map loop, and a fragile regex-based CSS minifier in the build script.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/botkit/src/components/Follower.tsx Outdated
Comment thread packages/botkit/src/pages.tsx Outdated
Comment thread packages/botkit/src/pages.tsx Outdated
Comment thread packages/botkit/scripts/build-assets.ts
@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.21429% with 1 line in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
packages/botkit/src/assets.ts 97.67% 0 Missing and 1 partial ⚠️
Files with missing lines Coverage Δ
packages/botkit/src/bot.ts 100.00% <ø> (ø)
packages/botkit/src/instance-impl.ts 77.61% <100.00%> (+0.12%) ⬆️
packages/botkit/src/message-impl.ts 88.69% <100.00%> (ø)
packages/botkit/src/static/fonts.ts 100.00% <ø> (ø)
packages/botkit/src/static/style.ts 100.00% <100.00%> (ø)
packages/botkit/src/static/version.ts 100.00% <100.00%> (ø)
packages/botkit/src/assets.ts 97.67% <97.67%> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1e62f4c87f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/botkit/src/static/fonts.ts
dahlia added 4 commits July 7, 2026 21:13
Call getActorHandle() only after confirming the actor has an id, so a
follower whose account was deleted renders the placeholder card instead
of risking a throw on a handleless actor.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
The banner alt checked `image instanceof Image`, but `image` is already
resolved to a URL, so it was always undefined; check `bot.image` and read
its name instead. The bot property list mapped entries to keyless
fragments, so build it with flatMap returning keyed <dt>/<dd> elements.

fedify-dev#36 (comment)
fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
Stash quoted strings before the whitespace and punctuation passes and
restore them afterwards, so structural characters inside a `content` or
`url()` value can never be rewritten. Output for the current stylesheet
is byte-for-byte unchanged.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
The Inter fonts are embedded in the published artifacts (dist/static and
src/static), so the SIL Open Font License notice has to travel with them.
Add it to the npm files list and stop excluding it from the JSR package;
only the woff2 source binaries are excluded now.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist

Copy link
Copy Markdown

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: 62553e6944

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request redesigns BotKit's web pages with a new, self-contained design language ('Canvas mode') that bundles fonts and stylesheets locally to eliminate external CDN dependencies. Key feedback highlights a critical Stored XSS vulnerability in Message.tsx where user-supplied content is rendered via dangerouslySetInnerHTML without sanitization; using textXss is recommended. Additionally, the copy-to-clipboard script in pages.tsx should include a fallback for non-secure contexts where navigator.clipboard is undefined, and the spread operator in instance-impl.ts should be replaced with explicit nullish coalescing to prevent undefined values from overwriting defaults.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/botkit/src/components/Message.tsx
Comment thread packages/botkit/src/components/Message.tsx
Comment thread packages/botkit/src/instance-impl.ts
Comment thread packages/botkit/src/pages.tsx
dahlia added 3 commits July 7, 2026 21:32
Post content is raw HTML from the originating ActivityPub object; for a
boosted post it comes from an untrusted remote actor, so rendering it
directly was a stored-XSS risk. Run it through htmlXss (the safe-tag
filter the message pipeline already uses) before injecting custom emojis.
textXss would have stripped all markup, so htmlXss is exported and used
instead. Adds a regression test.

fedify-dev#36 (comment)
fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
Spreading options.pages let a property explicitly set to undefined
overwrite its default, so a config passing { color: undefined } would
lose the green default. Resolve each option with nullish coalescing.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
navigator.clipboard is undefined in non-secure contexts, where the old
script marked the handle copied without copying anything. Mark success
only on an actual copy, and fall back to a hidden textarea with
execCommand when the async clipboard API is unavailable.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a complete redesign of BotKit's public web pages using a new, self-contained design language ('Canvas mode') and bundles the required stylesheet and web fonts locally to eliminate external CDN dependencies. It also adds a comprehensive design guide (DESIGN.md), support for theme configuration, and content sanitization against XSS. The review feedback highlights two key improvement opportunities: avoiding string coercion of message.content to prevent rendering literal 'null' or 'undefined' text on empty posts, and refactoring the FollowButton component to use relative DOM traversal instead of hardcoded IDs and global variables to prevent collisions when multiple buttons are rendered on the same page.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/botkit/src/components/Message.tsx Outdated
Comment thread packages/botkit/src/components/FollowButton.tsx Outdated
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: 2fb7681c5a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

dahlia added 2 commits July 7, 2026 21:50
A post with only attachments has no content, and the template literal
coerced that to the string "null" or "undefined". Read the content with
optional chaining and fall back to an empty string.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
The follow button relied on fixed ids and a global object, so rendering
several FollowButtons on one page would collide and every trigger would
open the first dialog. Open and close via relative DOM traversal
(nextElementSibling and closest('dialog')) instead, dropping the ids, the
global, and the inline script.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces Pico CSS with a self-contained, modern design language ('Canvas mode') for BotKit's web pages, bundling fonts and stylesheets directly into the package to eliminate external CDN dependencies. Key changes include a new asset codegen pipeline, support for light/dark themes, XSS sanitization for post content, and updated components using namespaced bk- classes. The review feedback identifies a potential bug where using .charAt(0) to extract the first letter of a bot's name could break on Unicode surrogate pairs (like emojis), and notes that the CSS minifier's regex in the build script fails to handle escaped quotes inside string literals.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/botkit/src/pages.tsx Outdated
Comment thread packages/botkit/src/pages.tsx Outdated
Comment thread packages/botkit/scripts/build-assets.ts Outdated
Relative sibling traversal was fragile to any element inserted between
the button and the dialog. Generate a unique dialog id per FollowButton
and open it with getElementById, which stays collision-free across
multiple buttons while decoupling from DOM structure.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request redesigns BotKit's public web pages with a new, self-contained design language ('Canvas mode') that replaces Pico CSS. The visual style is driven by the bot's accent color, supports light and dark themes automatically, and bundles stylesheet and font assets locally to eliminate external CDN dependencies. Additionally, the changes introduce a new theme option, integrate asset generation into the build pipeline, and sanitize post content against XSS. Feedback on the changes suggests using globalThis.crypto.randomUUID() instead of Math.random() to generate unique dialog IDs securely and prevent potential collisions.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/botkit/src/components/FollowButton.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a675ea685

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/botkit/src/components/Message.tsx Outdated
dahlia added 2 commits July 7, 2026 22:35
Math.random().toString(36) has degenerate cases (an empty or
scientific-notation suffix) and weaker collision guarantees. Use
crypto.randomUUID(), which is available on both Deno and Node 22+.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
The redesign kept an attachment's name only as the image alt, dropping
the visible caption the old renderer showed, so sighted visitors lost
that text on the profile, hashtag, and message pages. Render the name in
a figcaption in addition to the alt.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/botkit/src/message-impl.ts (1)

753-758: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add JSDoc (with @since) now that htmlXss is exported.

htmlXss was made exported without a JSDoc comment describing its purpose.

As per coding guidelines: "All exported APIs must have JSDoc comments describing purpose, parameters, and return values; APIs added in a specific version must include an @since tag."

📝 Proposed fix
+/**
+ * The HTML sanitizer used for message content rendered as HTML, allowing a
+ * safe subset of tags/attributes (including anchor `class`/`translate`).
+ * `@since` 0.x.y
+ */
 export const htmlXss = new xss.FilterXSS({
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/botkit/src/message-impl.ts` around lines 753 - 758, Add a JSDoc
comment for the exported htmlXss constant in message-impl.ts, describing that it
is the configured xss.FilterXSS instance used for HTML sanitization and include
an `@since` tag. Keep the comment directly above htmlXss so the exported API is
documented per the guideline; use the existing htmlXss symbol and its allowList
configuration as the reference point.

Source: Coding guidelines

🧹 Nitpick comments (9)
packages/botkit/scripts/build-assets.ts (1)

63-76: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Stash string literals before stripping comments to avoid corrupting CSS content.

minifyCss strips /* ... */ block comments (line 66) before stashing string literals (line 67). A future CSS string containing a comment-like sequence (e.g. content: "/* icon */") would have that sequence silently stripped instead of preserved. Reordering the two passes closes this gap with no behavior change for current input.

♻️ Proposed fix
   return css
-    .replace(/\/\*[\s\S]*?\*\//g, "")
     .replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g, (literal) => {
       literals.push(literal);
       return `__BKSTR${literals.length - 1}__`;
     })
+    .replace(/\/\*[\s\S]*?\*\//g, "")
     .replace(/\s+/g, " ")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/botkit/scripts/build-assets.ts` around lines 63 - 76, The minifyCss
helper currently removes block comments before it protects quoted strings, so
comment-like text inside CSS strings can be corrupted. Update minifyCss to first
stash string literals with the existing literal capture logic, then run the
comment-stripping replace, and keep the remaining whitespace/minification steps
unchanged so content like content: "/* icon */" is preserved.
packages/botkit/src/pages.tsx (1)

148-157: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Banner image can render without an alt attribute.

When bot.image has no name, alt resolves to undefined, so hono/jsx omits the attribute entirely rather than falling back to an empty string for a decorative image. Missing alt (as opposed to alt="") is worse for screen readers than an explicit empty alt.

Proposed fix
                 alt={bot.image instanceof Image
-                  ? bot.image.name?.toString() ?? undefined
-                  : undefined}
+                  ? bot.image.name?.toString() ?? ""
+                  : ""}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/botkit/src/pages.tsx` around lines 148 - 157, The banner image in
the JSX for the pages view can be rendered without an alt attribute when
bot.image has no name. Update the image rendering in pages.tsx so the img
element always receives an explicit alt value, using bot.image.name when
available and falling back to an empty string for decorative images; keep the
change localized to the existing image block that uses image.href and the Image
type check.
packages/botkit/src/pages.test.ts (1)

356-392: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Consider extending XSS coverage to the profile bio/fields.

This test verifies message content is sanitized, but the profile summary/properties fields (also injected via dangerouslySetInnerHTML in pages.tsx) aren't covered by an analogous test. If the bio/field HTML source isn't already sanitized (see comment on pages.tsx lines 194-214), a regression there wouldn't be caught here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/botkit/src/pages.test.ts` around lines 356 - 392, The current XSS
test only covers message content, so add an analogous test for profile rendering
to cover the `summary` and `properties` HTML used by `pages.tsx`. Extend
`message rendering` or add a nearby test that creates a profile with malicious
HTML in those fields, renders it through `BotImpl.fetch`, and asserts the safe
markup remains while script tags and javascript: URLs are stripped. Use the
existing `BotImpl`, `MemoryRepository`, and `dangerouslySetInnerHTML`-backed
profile page path as the target behavior.
packages/botkit/src/components/Follower.tsx (2)

43-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate icon-URL extraction logic.

This iconUrl derivation is duplicated verbatim in Message.tsx (lines 56-60 in that file). Consider extracting a shared helper (e.g., getLinkHref(link: Link | URL | null): string | null) to avoid drift between the two.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/botkit/src/components/Follower.tsx` around lines 43 - 47, The icon
URL extraction logic in Follower.tsx is duplicated in Message.tsx, so centralize
it in a shared helper to prevent the two paths from drifting. Extract the
`authorIcon.url` / `Link` / `URL` handling into a reusable function such as
`getLinkHref` in a common utility module, then update both Follower and Message
to call that helper instead of inlining the ternary logic.

53-61: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Missing alt fallback when icon name is unavailable.

When authorIcon?.name is null, alt becomes undefined and the <img> renders with no alt attribute at all, leaving it without an accessible name for screen readers.

♿ Proposed fix
           <img
             src={iconUrl}
-            alt={authorIcon?.name?.toString() ?? undefined}
+            alt={authorIcon?.name?.toString() ?? ""}
             loading="lazy"
           />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/botkit/src/components/Follower.tsx` around lines 53 - 61, In
Follower’s image rendering branch, the current alt prop can resolve to undefined
when authorIcon?.name is missing, which leaves the img without an accessible
name. Update the Follower component’s img alt handling so it always provides a
meaningful fallback string when authorIcon.name is unavailable, while keeping
the existing iconUrl-based conditional rendering intact.
packages/botkit/src/components/Message.tsx (2)

81-87: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Same missing alt fallback as Follower.tsx.

alt={authorIcon?.name?.toString() ?? undefined} drops the alt attribute entirely instead of using an empty-string fallback when the icon has no name.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/botkit/src/components/Message.tsx` around lines 81 - 87, The image
in Message.tsx is missing the same accessibility fallback used elsewhere,
because the alt value currently becomes undefined when authorIcon has no name.
Update the Message component’s img markup to use an empty-string fallback for
alt instead of omitting the attribute, matching the behavior of Follower.tsx and
preserving the intended accessibility handling.

111-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Non-null assertion on a.url conflicts with the "avoid unsafe assertions" guideline.

a.url!.href bypasses type checking even though the preceding .filter((a) => ... && a.url != null) (line 63) isn't a type predicate, so TS can't actually verify this at the call site.

As per coding guidelines, "avoid unsafe assertions such as as unknown as ..." — the non-null assertion operator has the same "trust me" risk profile.

🔧 Proposed fix using a type-narrowing filter
   const images = attachments
     .filter((a) => a instanceof Image || a instanceof Document)
-    .filter((a) => a.mediaType?.startsWith("image/") && a.url != null);
+    .filter(
+      (a): a is (typeof a) & { url: NonNullable<typeof a.url> } =>
+        a.mediaType?.startsWith("image/") === true && a.url != null,
+    );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/botkit/src/components/Message.tsx` around lines 111 - 124, The image
rendering in Message.tsx still uses an unsafe non-null assertion on a.url in the
images.map block. Update the filtering logic earlier in Message so it is a
proper type-narrowing predicate (or otherwise guarantees a.url is non-null at
the call site), then remove the a.url! access and use the narrowed type directly
when building the img src. Keep the change localized to the images pipeline in
Message and the image render path.

Source: Coding guidelines

packages/botkit/src/components/Layout.tsx (2)

26-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

ACCENT_HEX duplicates the accent presets in botkit.css.

The 20 hex values here (lines 26-47) mirror the --botkit-accent values in packages/botkit/src/css/botkit.css (lines 134-153) verbatim. Since these two files aren't generated from a single source of truth, adding/editing a color in one place (e.g., updating a preset in botkit.css) can silently desync the theme-color meta tag from the actual page accent.

Consider generating this lookup table from the same source data used for the CSS accent presets (e.g., via scripts/build-assets.ts), or importing a shared JSON/TS module referenced by both.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/botkit/src/components/Layout.tsx` around lines 26 - 47, ACCENT_HEX
in Layout.tsx is duplicated from the accent preset values in botkit.css, so it
can drift from the actual theme colors. Move the accent preset source into a
shared module or generated asset used by both Layout’s theme-color lookup and
the CSS presets, and update the Layout component to consume that shared source
via ACCENT_HEX so the mapping stays in sync.

139-148: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

FeedIcon's size prop isn't documented.

The JSDoc only states the glyph's purpose but omits the size parameter.

As per coding guidelines, "All exported APIs must have JSDoc comments describing purpose, parameters, and return values."

📝 Proposed fix
-/** An Atom/RSS feed glyph. */
+/**
+ * An Atom/RSS feed glyph.
+ *
+ * `@param` size The glyph's width/height in pixels.
+ */
 export function FeedIcon({ size = 16 }: { readonly size?: number }) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/botkit/src/components/Layout.tsx` around lines 139 - 148, FeedIcon
is an exported API but its JSDoc is missing the size parameter description.
Update the JSDoc above FeedIcon in Layout.tsx to document its purpose, the
optional size prop, and the return value so it matches the project’s
exported-API documentation guideline. Keep the comment aligned with the FeedIcon
symbol and make sure the size default behavior is mentioned.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@DESIGN.md`:
- Around line 67-71: The Canvas/Expression boundary wording is inconsistent with
the footer-credit exception, so update the relevant guidance in DESIGN.md to
make it clear that only full Expression-mode surfaces are disallowed in Canvas
while the “Powered by BotKit” footer credit remains the intended exception.
Adjust the phrasing around the instance index and footer credit language to
preserve the “quiet token” exception and avoid implying the footer itself is
prohibited.

In `@packages/botkit/src/assets.ts`:
- Around line 59-66: Add the missing `@since` tags to the JSDoc for the new public
exports in assets.ts: ASSET_VERSION, ASSET_PATH_PREFIX, STYLESHEET_PATH, and
serveAsset. Update the existing comments near these symbols so each exported API
clearly includes its version annotation, and make sure any related JSDoc in
serveAsset also follows the same guideline.

In `@packages/botkit/src/css/botkit.css`:
- Around line 26-40: Fix the remaining stylelint errors in botkit.css by
aligning the affected declarations with the lint rules. In the two `@font-face`
blocks, remove the quotes from the Inter font-family name, and update the other
flagged value keywords to lowercase so Menlo becomes menlo and
optimizeLegibility becomes optimizelegibility. Use the existing `@font-face` rules
and the related font/typography declarations as the reference points.
- Around line 631-638: The .bk-page-title rule in botkit.css uses deprecated
word-break: break-word, so replace it with the modern wrapping behavior using
overflow-wrap: anywhere while keeping the same long-title/handle wrapping
intent. Update the .bk-page-title selector only, and remove the deprecated
word-break declaration so Stylelint passes.

In `@packages/botkit/src/fonts/LICENSE-inter.txt`:
- Line 1: The first line of LICENSE-inter.txt is garbled because two separate
copyright notices were concatenated into one line. Update the Inter license text
so the general Inter Project copyright notice and the
Inter-Italic[opsz,wght].ttf copyright notice are split into separate lines,
preserving the intended wording and formatting in this license file.

In `@packages/botkit/src/pages.tsx`:
- Line 175: The initial avatar fallback in the page rendering logic uses
`bot.name || bot.username`, which should be changed to nullish coalescing to
match the file’s default-value guideline. Update the expression in `pages.tsx`
where the avatar initial is derived, and apply the same operator fix to the
matching `multiApp` landing page usage so `name` only falls back when it is null
or undefined. Refer to the `bot.name ?? bot.username` pattern already used
elsewhere in this file as the correct behavior.

---

Outside diff comments:
In `@packages/botkit/src/message-impl.ts`:
- Around line 753-758: Add a JSDoc comment for the exported htmlXss constant in
message-impl.ts, describing that it is the configured xss.FilterXSS instance
used for HTML sanitization and include an `@since` tag. Keep the comment directly
above htmlXss so the exported API is documented per the guideline; use the
existing htmlXss symbol and its allowList configuration as the reference point.

---

Nitpick comments:
In `@packages/botkit/scripts/build-assets.ts`:
- Around line 63-76: The minifyCss helper currently removes block comments
before it protects quoted strings, so comment-like text inside CSS strings can
be corrupted. Update minifyCss to first stash string literals with the existing
literal capture logic, then run the comment-stripping replace, and keep the
remaining whitespace/minification steps unchanged so content like content: "/*
icon */" is preserved.

In `@packages/botkit/src/components/Follower.tsx`:
- Around line 43-47: The icon URL extraction logic in Follower.tsx is duplicated
in Message.tsx, so centralize it in a shared helper to prevent the two paths
from drifting. Extract the `authorIcon.url` / `Link` / `URL` handling into a
reusable function such as `getLinkHref` in a common utility module, then update
both Follower and Message to call that helper instead of inlining the ternary
logic.
- Around line 53-61: In Follower’s image rendering branch, the current alt prop
can resolve to undefined when authorIcon?.name is missing, which leaves the img
without an accessible name. Update the Follower component’s img alt handling so
it always provides a meaningful fallback string when authorIcon.name is
unavailable, while keeping the existing iconUrl-based conditional rendering
intact.

In `@packages/botkit/src/components/Layout.tsx`:
- Around line 26-47: ACCENT_HEX in Layout.tsx is duplicated from the accent
preset values in botkit.css, so it can drift from the actual theme colors. Move
the accent preset source into a shared module or generated asset used by both
Layout’s theme-color lookup and the CSS presets, and update the Layout component
to consume that shared source via ACCENT_HEX so the mapping stays in sync.
- Around line 139-148: FeedIcon is an exported API but its JSDoc is missing the
size parameter description. Update the JSDoc above FeedIcon in Layout.tsx to
document its purpose, the optional size prop, and the return value so it matches
the project’s exported-API documentation guideline. Keep the comment aligned
with the FeedIcon symbol and make sure the size default behavior is mentioned.

In `@packages/botkit/src/components/Message.tsx`:
- Around line 81-87: The image in Message.tsx is missing the same accessibility
fallback used elsewhere, because the alt value currently becomes undefined when
authorIcon has no name. Update the Message component’s img markup to use an
empty-string fallback for alt instead of omitting the attribute, matching the
behavior of Follower.tsx and preserving the intended accessibility handling.
- Around line 111-124: The image rendering in Message.tsx still uses an unsafe
non-null assertion on a.url in the images.map block. Update the filtering logic
earlier in Message so it is a proper type-narrowing predicate (or otherwise
guarantees a.url is non-null at the call site), then remove the a.url! access
and use the narrowed type directly when building the img src. Keep the change
localized to the images pipeline in Message and the image render path.

In `@packages/botkit/src/pages.test.ts`:
- Around line 356-392: The current XSS test only covers message content, so add
an analogous test for profile rendering to cover the `summary` and `properties`
HTML used by `pages.tsx`. Extend `message rendering` or add a nearby test that
creates a profile with malicious HTML in those fields, renders it through
`BotImpl.fetch`, and asserts the safe markup remains while script tags and
javascript: URLs are stripped. Use the existing `BotImpl`, `MemoryRepository`,
and `dangerouslySetInnerHTML`-backed profile page path as the target behavior.

In `@packages/botkit/src/pages.tsx`:
- Around line 148-157: The banner image in the JSX for the pages view can be
rendered without an alt attribute when bot.image has no name. Update the image
rendering in pages.tsx so the img element always receives an explicit alt value,
using bot.image.name when available and falling back to an empty string for
decorative images; keep the change localized to the existing image block that
uses image.href and the Image type check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 01e441cd-eb5c-4f4e-ab83-20df84be33b2

📥 Commits

Reviewing files that changed from the base of the PR and between 9fa2d89 and 1a675ea.

⛔ Files ignored due to path filters (2)
  • packages/botkit/src/fonts/inter-italic.woff2 is excluded by !**/*.woff2
  • packages/botkit/src/fonts/inter.woff2 is excluded by !**/*.woff2
📒 Files selected for processing (23)
  • AGENTS.md
  • CHANGES.md
  • DESIGN.md
  • docs/concepts/bot.md
  • mise.toml
  • packages/botkit/deno.json
  • packages/botkit/package.json
  • packages/botkit/scripts/build-assets.ts
  • packages/botkit/src/assets.ts
  • packages/botkit/src/bot.ts
  • packages/botkit/src/components/FollowButton.tsx
  • packages/botkit/src/components/Follower.tsx
  • packages/botkit/src/components/Layout.tsx
  • packages/botkit/src/components/Message.test.tsx
  • packages/botkit/src/components/Message.tsx
  • packages/botkit/src/css/botkit.css
  • packages/botkit/src/fonts/LICENSE-inter.txt
  • packages/botkit/src/instance-impl.ts
  • packages/botkit/src/message-impl.ts
  • packages/botkit/src/pages.test.ts
  • packages/botkit/src/pages.tsx
  • packages/botkit/src/static/fonts.ts
  • packages/botkit/src/static/style.ts

Comment thread DESIGN.md
Comment thread packages/botkit/src/assets.ts Outdated
Comment thread packages/botkit/src/css/botkit.css
Comment thread packages/botkit/src/css/botkit.css
Comment thread packages/botkit/src/fonts/LICENSE-inter.txt Outdated
Comment thread packages/botkit/src/pages.tsx Outdated

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a major redesign of BotKit's public web pages with a new, self-contained design language (Canvas mode) that replaces Pico CSS. The assets, including the stylesheet and web fonts, are now bundled locally and served via content-addressed paths, eliminating external CDN dependencies and ensuring a zero-build-step experience. Additionally, a new theme option has been added to support light, dark, and automatic color schemes, and post content is now sanitized against XSS. Feedback on these changes suggests updating package.json to specify "sideEffects": true because BotKit relies on a global polyfill for Temporal, which modifies the global scope.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/botkit/package.json Outdated
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 09090a877b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

dahlia added 7 commits July 7, 2026 22:43
htmlXss is exported for use by the message component, so it needs JSDoc
per the project's API documentation guideline. Describe what it sanitizes
and tag the version it became public.

fedify-dev#36 (review)

Assisted-by: Claude Code:claude-opus-4-8
The absolute wording conflicted with the footer-credit exception, so ban
full Expression-mode surfaces rather than any trace of Expression.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
Use overflow-wrap: anywhere, the modern equivalent, for the page title.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
The bundled notice concatenated two copyright lines into one; split them
so each font's attribution reads on its own line.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
The optional-chaining guard already prevents an empty-string name from
throwing, so the fallback uses ?? to match the file's convention and the
surrounding bot.name ?? bot.username usage.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
The build injects a global Temporal polyfill (Date.prototype.toTemporalInstant),
so bundlers must not tree-shake the package's modules away.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a redesigned, self-contained design language for BotKit's web pages, replacing Pico CSS with a custom, quiet 'Canvas mode' theme. It bundles the stylesheet and Inter fonts locally to eliminate external CDN dependencies, utilizing a content-addressed asset pipeline with runtime serving. Key improvements include a new DESIGN.md guide, color scheme customization options, and robust XSS sanitization for post content. Feedback on these changes highlights an opportunity to optimize performance by pre-computing the asset fingerprint at build time rather than hashing at runtime, as well as a recommendation to use array indices as fallback keys in JSX list rendering to prevent potential rendering issues.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/botkit/src/assets.ts Outdated
Comment thread packages/botkit/src/pages.tsx Outdated
Comment thread packages/botkit/src/pages.tsx Outdated
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 13c7b5584d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

dahlia added 2 commits July 7, 2026 23:05
computeAssetVersion() hashed the stylesheet and every font on each module
import, that is on every cold start. Move that djb2 into the codegen
step, emit it as src/static/version.ts, and import it, so no hashing runs
at runtime. The fingerprint value is unchanged.

fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
Fall back to the array index when a message has no id, so mapped profile
and hashtag posts always carry a key.

fedify-dev#36 (comment)
fedify-dev#36 (comment)

Assisted-by: Claude Code:claude-opus-4-8
@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

@codex review

@dahlia

dahlia commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a major redesign of BotKit's public web pages (profile, posts, follower list, and multi-bot index) with a custom, self-contained design language called "Canvas mode" to replace Pico CSS. It establishes a local asset pipeline that minifies CSS and base64-encodes the Inter font into static TypeScript modules, allowing the assets to be served locally with content-addressed fingerprinting and immutable caching without requiring an external CDN or user build step. Additionally, it introduces a new theme option (supporting auto, light, and dark modes), sanitizes post content against XSS, and updates all page components to use the new bk- namespaced styles. I have no feedback to provide as there are no review comments and the implementation is robust and well-tested.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 2fedd512ad

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@dahlia dahlia merged commit 146f217 into fedify-dev:main Jul 7, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant