Skip to content

misc: UI improvements and docs updates#345

Merged
jamiepine merged 1 commit into
mainfrom
misc/ui-fixes
Mar 7, 2026
Merged

misc: UI improvements and docs updates#345
jamiepine merged 1 commit into
mainfrom
misc/ui-fixes

Conversation

@jamiepine

@jamiepine jamiepine commented Mar 7, 2026

Copy link
Copy Markdown
Member

Summary

  • Agent config General tab: Add a new "General" section to the agent config page with editable display name and role fields (previously only accessible from the topology graph edit dialog)
  • Agent header display name: Show the agent's display name alongside the ID in the page header bar across all agent routes
  • Changelog in settings: Add a changelog section to settings that parses CHANGELOG.md into per-release cards, served via a new /changelog API endpoint with embedded content
  • Markdown HTML support: Add rehype-raw plugin so HTML tags in markdown content render correctly
  • Docs: Document environment variables in config reference, add dev setup guide to quickstart, add projects design document

Note

Changes Overview

This PR brings UI improvements and comprehensive documentation updates. The frontend now exposes agent configuration (display name and role) that was previously only editable through the topology graph. The header consistently shows the agent's display name alongside its ID across all routes. A new changelog view in settings displays release history parsed from CHANGELOG.md.

Documentation expanded with environment variable reference (SPACEBOT_DIR, SPACEBOT_DEPLOYMENT, etc.), a dev setup guide for running isolated instances side-by-side, and a detailed design document for the upcoming Projects feature. The markdown renderer now supports raw HTML via rehype-raw, enabling richer content rendering.

Key files: agent config UI (GeneralEditor), header rendering, changelog parsing, markdown components, API changelog endpoint, and 600+ lines of Projects design documentation.

Written by Tembo for commit 4488ae5. This will update automatically on new commits.

- Add General section to agent config page with display_name and role fields
- Show agent display name alongside ID in the page header
- Add changelog section to settings with per-release card layout
- Add rehype-raw for HTML-in-markdown rendering
- Add changelog API endpoint serving embedded CHANGELOG.md
- Document environment variables and dev setup in docs
- Add projects design document
@coderabbitai

coderabbitai Bot commented Mar 7, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The pull request adds changelog functionality across frontend and backend, introduces a comprehensive Projects feature design document, and updates user-facing documentation with environment variables and development setup guidance. Changes span documentation, API endpoints, React components, and utility functions without modifying core runtime behavior.

Changes

Cohort / File(s) Summary
Documentation Updates
docs/content/docs/(configuration)/config.mdx, docs/content/docs/(getting-started)/quickstart.mdx
Adds Environment Variables reference section to config documentation and new Development setup section to quickstart with SPACEBOT_DIR examples for parallel instances.
Projects Design Document
docs/design-docs/projects.md
Comprehensive feature specification for Projects functionality including problem statement, data schema, database migrations, prompt injection changes, tool modifications, API endpoints, UI additions, phased implementation plan, and open design questions.
Changelog Feature – Backend
src/api/server.rs, src/api/settings.rs, src/self_awareness.rs
Adds /changelog API route and endpoint handler that returns embedded changelog content via new changelog_content() accessor function.
Changelog Feature – Frontend
interface/src/api/client.ts, interface/src/routes/Settings.tsx, interface/src/components/Markdown.tsx
Implements changelog display in Settings with parsing logic, adds API client method, and enables raw HTML rendering in Markdown via rehype-raw plugin.
Agent Configuration & Routing
interface/src/routes/AgentConfig.tsx, interface/src/router.tsx
Introduces General section to AgentConfig with in-place editor for agent metadata (display name, role), adds data fetching for agent details in router header, and implements optimistic UI updates with cache invalidation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #311: Shares overlapping implementation of changelog content accessors and API/UI wiring for changelog data (changelog_content() function and /changelog endpoint integration).
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'misc: UI improvements and docs updates' is vague and generic, using non-descriptive terms that fail to convey the specific changes made in the changeset. Consider a more descriptive title that highlights the primary changes, such as 'Add General tab to agent config, changelog UI, and project design docs' or 'Add agent display name UI, changelog section, and project documentation'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description comprehensively details all major changes across frontend UI improvements and documentation, directly relating to the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch misc/ui-fixes

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 and usage tips.

<div className={className ? `markdown ${className}` : "markdown"}>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeRaw]}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Enabling rehypeRaw here makes all Markdown render raw HTML. This component is used for chat/task content too, so if any of that is user-controlled this becomes an XSS footgun.

Consider gating raw HTML to trusted sources only (e.g. changelog/docs), or pairing rehype-raw with a sanitizer/allowlist.

Comment on lines +358 to +365
useEffect(() => {
onDirtyChange(localDirty);
}, [localDirty, onDirtyChange]);

const handleSave = useCallback(() => {
onSave({ display_name: localDisplayName, role: localRole });
setLocalDirty(false);
}, [onSave, localDisplayName, localRole]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

handleSave clears localDirty, which immediately triggers the sync useEffect above and can overwrite the inputs with the previous displayName/role before the mutation refetch completes (and it also drops the edits on save failure).

One approach is to keep localDirty true until the props catch up to the saved values:

Suggested change
useEffect(() => {
onDirtyChange(localDirty);
}, [localDirty, onDirtyChange]);
const handleSave = useCallback(() => {
onSave({ display_name: localDisplayName, role: localRole });
setLocalDirty(false);
}, [onSave, localDisplayName, localRole]);
useEffect(() => {
onDirtyChange(localDirty);
}, [localDirty, onDirtyChange]);
useEffect(() => {
if (localDirty && localDisplayName === displayName && localRole === role) {
setLocalDirty(false);
}
}, [localDirty, localDisplayName, localRole, displayName, role]);
const handleSave = useCallback(() => {
onSave({ display_name: localDisplayName, role: localRole });
}, [onSave, localDisplayName, localRole]);

}

function ChangelogSection() {
const { data: changelog, isLoading } = useQuery<string>({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Minor UX: if api.changelog fails, this currently falls through to the same "No changelog available" empty state. Might be worth surfacing an explicit error state so users can distinguish "failed to load" vs "no releases parsed".

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
docs/design-docs/projects.md (2)

13-21: Add language specifier to fenced code block.

The directory structure code block should have a language specifier for proper rendering.

📝 Proposed fix
-```
+```text
 ~/Projects/spacebot/            ← project root
 ├── spacebot/                   ← repo (core agent)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/design-docs/projects.md` around lines 13 - 21, The fenced code block
showing the directory tree lacks a language specifier which can break syntax
highlighting; update the fenced block in docs/design-docs/projects.md by adding
a language tag (e.g., "text") immediately after the opening triple backticks for
the directory structure block so it reads ```text and leave the content
unchanged.

309-321: Add language specifier to tool definition code block.

Consider using yaml or text for the tool schema definition.

📝 Proposed fix
-```
+```yaml
 project_manage:
   action: "create" | "scan" | "add_repo" | "create_worktree" | "remove_worktree" | "list" | "disk_usage"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/design-docs/projects.md` around lines 309 - 321, The YAML-like tool
schema block for "project_manage" lacks a language specifier; update the fenced
code block that defines project_manage (the block starting with project_manage:
and listing action, project_id, name, etc.) to add a language tag (e.g.,
```yaml) so syntax highlighting and tooling recognize it as YAML; ensure only
the opening fence is changed to include the language and leave the schema
contents unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@interface/src/components/Markdown.tsx`:
- Line 3: The Markdown component currently imports and uses rehype-raw which
allows rendering unsanitized HTML; update the component by importing
rehype-sanitize (e.g. rehypeSanitize) and include it in the rehype pipeline
immediately after rehypeRaw so raw HTML is passed through a sanitizer; modify
the sanitization options if needed to explicitly allow safe tags/attributes for
your use cases, ensuring the component (Markdown) uses [rehypeRaw,
rehypeSanitize] order when building remark/rehype processors.

---

Nitpick comments:
In `@docs/design-docs/projects.md`:
- Around line 13-21: The fenced code block showing the directory tree lacks a
language specifier which can break syntax highlighting; update the fenced block
in docs/design-docs/projects.md by adding a language tag (e.g., "text")
immediately after the opening triple backticks for the directory structure block
so it reads ```text and leave the content unchanged.
- Around line 309-321: The YAML-like tool schema block for "project_manage"
lacks a language specifier; update the fenced code block that defines
project_manage (the block starting with project_manage: and listing action,
project_id, name, etc.) to add a language tag (e.g., ```yaml) so syntax
highlighting and tooling recognize it as YAML; ensure only the opening fence is
changed to include the language and leave the schema contents unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0b2e4d0a-4c3b-4f5f-8ad4-ddd1c261d56b

📥 Commits

Reviewing files that changed from the base of the PR and between e7cf779 and 4488ae5.

⛔ Files ignored due to path filters (2)
  • interface/bun.lock is excluded by !**/*.lock, !**/*.lock
  • interface/package.json is excluded by !**/*.json
📒 Files selected for processing (11)
  • docs/content/docs/(configuration)/config.mdx
  • docs/content/docs/(getting-started)/quickstart.mdx
  • docs/design-docs/projects.md
  • interface/src/api/client.ts
  • interface/src/components/Markdown.tsx
  • interface/src/router.tsx
  • interface/src/routes/AgentConfig.tsx
  • interface/src/routes/Settings.tsx
  • src/api/server.rs
  • src/api/settings.rs
  • src/self_awareness.rs

@@ -1,5 +1,6 @@
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import rehypeRaw from "rehype-raw";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

rehype-sanitize npm package usage with rehype-raw

💡 Result:

To safely use rehype-raw (which turns embedded/raw HTML into real nodes), run rehype-sanitize after rehype-raw to drop anything not explicitly allowed by the sanitizer schema. This is the recommended pattern because enabling raw HTML is “dangerous” unless you sanitize. [1] [2]

Unified / remark pipeline (Markdown → HAST → HTML)

import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeRaw from 'rehype-raw'
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'

const file = await unified()
  .use(remarkParse)
  // keep raw HTML from markdown as "raw" nodes (dangerous unless you sanitize later)
  .use(remarkRehype, { allowDangerousHtml: true })
  // parse those raw nodes into real HTML AST nodes
  .use(rehypeRaw)
  // sanitize the resulting tree (defaults are fairly strict)
  .use(rehypeSanitize, defaultSchema)
  .use(rehypeStringify)
  .process(markdown)

Order and the allowDangerousHtml + rehype-raw + rehype-sanitize combo are shown in the remark-rehype docs, and rehype-raw explicitly warns to sanitize if you combine it with user content. [1] [2]

Allowing extra attributes/classes (common need)

If you need to allow specific things (e.g., className for syntax highlighting), extend defaultSchema and pass it to rehype-sanitize. [3]

import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'

const schema = {
  ...defaultSchema,
  attributes: {
    ...defaultSchema.attributes,
    code: [...(defaultSchema.attributes.code || []), ['className']],
    span: [...(defaultSchema.attributes.span || []), ['className']],
  },
}

Key rule: anything that creates/rehydrates HTML nodes (rehype-raw) should happen before sanitization; anything that adds risky nodes/attrs should be assumed unsafe unless your schema allows it. [1] [2] [3]

Sources:
[1] remark-rehype example showing allowDangerousHtml: truerehype-rawrehype-sanitize [1]
[2] rehype-raw docs warning to sanitize when used with user content [2]
[3] rehype-sanitize docs (schema-based allowlist; defaultSchema) [3]


🏁 Script executed:

# First, locate and read Markdown.tsx
find . -name "Markdown.tsx" -type f

Repository: spacedriveapp/spacebot

Length of output: 105


🏁 Script executed:

# Search for rehypeSanitize usage in the codebase
rg "rehypeSanitize" --type ts --type tsx

Repository: spacedriveapp/spacebot

Length of output: 93


🏁 Script executed:

# Check the current state of Markdown.tsx including the imports and rehypePlugins usage
find . -name "Markdown.tsx" -type f -exec wc -l {} \;

Repository: spacedriveapp/spacebot

Length of output: 108


🏁 Script executed:

# Search for rehypeSanitize usage - try without file type flag
rg "rehypeSanitize"

Repository: spacedriveapp/spacebot

Length of output: 48


🏁 Script executed:

# Read the Markdown.tsx file to see current implementation
cat -n ./interface/src/components/Markdown.tsx

Repository: spacedriveapp/spacebot

Length of output: 882


🏁 Script executed:

# Check usage of Markdown component in the codebase
rg "Markdown" ./interface/src/components/ -A 2 -B 2 | head -100

Repository: spacedriveapp/spacebot

Length of output: 3293


🏁 Script executed:

# Search for specific components that use Markdown
rg "CortexChatPanel|WebChatPanel|ChannelDetail|AgentWorkers" ./interface/src/ -l

Repository: spacedriveapp/spacebot

Length of output: 381


🏁 Script executed:

# Check ChannelDetail.tsx for Markdown usage
rg "Markdown" ./interface/src/routes/ChannelDetail.tsx -B 3 -A 3

Repository: spacedriveapp/spacebot

Length of output: 1343


🏁 Script executed:

# Check AgentWorkers.tsx for Markdown usage
rg "Markdown" ./interface/src/routes/AgentWorkers.tsx -B 3 -A 3

Repository: spacedriveapp/spacebot

Length of output: 748


🏁 Script executed:

# Check what content sources are being passed to Markdown in WebChatPanel
sed -n '1,150p' ./interface/src/components/WebChatPanel.tsx | cat -n

Repository: spacedriveapp/spacebot

Length of output: 6912


XSS vulnerability: rehype-raw renders unsanitized HTML from untrusted sources.

The Markdown component is used to render content from multiple sources including external chat messages (Discord/Slack/Telegram), worker execution results, and assistant responses. Enabling rehype-raw without sanitization allows malicious HTML like <script>, <img onerror="...">, or event handlers to execute in the browser.

Add rehype-sanitize after rehype-raw to allowlist safe HTML tags:

🛡️ Proposed fix: Add rehype-sanitize
 import ReactMarkdown from "react-markdown";
 import remarkGfm from "remark-gfm";
 import rehypeRaw from "rehype-raw";
+import rehypeSanitize from "rehype-sanitize";

 export function Markdown({
   children,
   className,
 }: {
   children: string;
   className?: string;
 }) {
   return (
     <div className={className ? `markdown ${className}` : "markdown"}>
       <ReactMarkdown
         remarkPlugins={[remarkGfm]}
-        rehypePlugins={[rehypeRaw]}
+        rehypePlugins={[rehypeRaw, rehypeSanitize]}
         components={{
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@interface/src/components/Markdown.tsx` at line 3, The Markdown component
currently imports and uses rehype-raw which allows rendering unsanitized HTML;
update the component by importing rehype-sanitize (e.g. rehypeSanitize) and
include it in the rehype pipeline immediately after rehypeRaw so raw HTML is
passed through a sanitizer; modify the sanitization options if needed to
explicitly allow safe tags/attributes for your use cases, ensuring the component
(Markdown) uses [rehypeRaw, rehypeSanitize] order when building remark/rehype
processors.

@jamiepine jamiepine merged commit 9d39ae8 into main Mar 7, 2026
5 checks passed
rktmeister pushed a commit to rktmeister/spacebot that referenced this pull request Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant