feat: color-code projects as an accessibility aid - #8772

Open
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding
Open

feat: color-code projects as an accessibility aid#8772
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding

Conversation

@IAmJSD

@IAmJSDIAmJSD commented Aug 30, 2026

Copy link
Copy Markdown

Note

This PR — code and description — was written by Claude Code (Claude Fable 5), working in Astrid Gealer's session at Infrawrench.

What

Adds the ability to color-code repos/projects as an accessibility feature, so they can be told apart at a glance. Pick a color from a nine-swatch palette (plus a "no color" option) in the sidebar's project actions dialog; it then shows as a small dot everywhere the project identifies itself:

  • sidebar thread cards and compact rows (V2), search results, and thread tooltips
  • the project filter menu and its trigger
  • the Sidebar V1 project group header
  • the chat header

How

Follows the precedent set by pinned-thread ordering (#5581) for server-synced per-entity state:

  • Contracts: optional ProjectColor field on OrchestrationProject(Shell), project.meta.update, and ProjectMetaUpdatedPayload — optional/nullable everywhere so old servers and clients interop. New projectColor capability flag so clients hide the picker instead of sending commands a pre-color server would reject.
  • Server: migration 039_ProjectionProjectsColor adds a color column to projection_projects; decider, in-memory projector, projection pipeline, and snapshot queries thread the field through.
  • Web: projectColors.ts (palette + group-color resolution) and ProjectColor.tsx (ProjectColorDot, ProjectColorPicker). Colors are persisted as palette names and rendered via Tailwind color tokens, so dots stay legible in both light and dark themes. Dots are aria-hidden (the project name is always present as text); picker swatches carry labels and aria-pressed state.
  • Grouped projects (same repo across environments) resolve to one color, and setting it in any environment colors the group.

Testing

  • New decider/projector tests (set / clear / leave-unchanged) and a persistence round-trip test.
  • Full monorepo typecheck and lint clean; web (1942), client-runtime (588), contracts (226), and server (1912) suites pass. The only server-suite failures are 6 pre-existing environment-dependent ones (service-launcher version mismatch on the dev box), identical on a clean tree.

Not included (possible follow-ups)

  • Mobile parity (mobile ProjectFavicon sites don't render dots yet).
  • Dots in the command palette / draft-hero project pickers.

🤖 Generated with Claude Code


Note

Medium Risk
Touches orchestration commands, a DB migration on projection_projects, and multi-environment fan-out in project settings; mitigated by optional wire fields and capability gating for version skew.

Overview
Adds optional project colors end to end so repos can be distinguished by a small colored dot in the sidebar, chat header, and project settings.

Contracts & server: Introduces ProjectColor and nullable color on project snapshots and project.meta.update / project.meta-updated (omitted when unchanged). Migration 044_ProjectionProjectsColor adds color to projection_projects; the decider, projector, SQL projections, and snapshot queries persist and expose it. Servers advertise a projectColor capability so older peers are not sent unknown fields.

Web: Palette helpers (projectColors.ts) plus ProjectColorDot / ProjectColorPicker. Settings fans color out to capability-aware group members; grouped logical projects share one resolved color across environments. Dots are decorative (aria-hidden); the picker is labeled for accessibility.

Tests & docs: Decider/projector and DB round-trip coverage, plus user docs for setting colors.

Reviewed by Cursor Bugbot for commit faf3e3f. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add end-to-end project color support as an accessibility aid

  • Introduces a nullable color field across OrchestrationProject, OrchestrationProjectShell, ProjectMetaUpdateCommand, and ProjectMetaUpdatedPayload in orchestration.ts, plus an optional projectColor capability flag in environment.ts
  • Adds migration 44 to add a color TEXT column to projection_projects in 044_ProjectionProjectsColor.ts; the projection pipeline, projector, and snapshot queries now persist and return color
  • The server advertises projectColor: true in ServerEnvironment.ts; the project settings UI in ProjectSettingsPanel.tsx only renders the new ProjectColorPicker when at least one group member is color-capable, and fans out color updates only to capable members
  • Sidebar, thread rows, tooltips, search results, draft rows, chat header, and legacy sidebar now display a ProjectColorDot using group-level color resolution via new utilities in projectColors.ts
  • Behavioral Change: project.meta-updated events now conditionally carry color (absent = unchanged, null = cleared); getSnapshot, getShellSnapshot, and getActiveProjectById responses now include color, which older clients may ignore under version skew. The capability flag gates the UI; servers not advertising projectColor will not show the picker.

Macroscope summarized faf3e3f.

@coderabbitai

coderabbitaiBot commented Aug 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 70ad8f0b-414a-4acb-9bca-9b5a87efd236

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 30, 2026
Comment threadapps/web/src/components/ChatView.tsx Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/projectColors.ts

@macroscopeappmacroscopeappBot 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.

One finding on the new web palette module. Everything else — capability gating and RPC both resolved from member.environmentId, activeProject scoped to the thread's environment, ProjectColorDot placements inside MenuRadioItem's children wrapper, and the raw swatch buttons (exempt as swatches) — looks consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/projectColors.ts Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/components/ChatView.tsx Outdated
@macroscopeapp

macroscopeappBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a persisted, cross-environment project-color capability with a new settings workflow and rendering across several production surfaces. Although it is opt-in and backward-compatible for uncolored projects, its cross-stack scope and multi-environment write behavior warrant human review.

You can add or adjust custom eligibility rules. Learn more.

Adds a per-project color, chosen from a theme-aware nine-swatch palette
in the sidebar's project actions dialog, shown as a small dot wherever
the project identifies itself: sidebar thread cards and compact rows,
search results, tooltips, the project filter menu, the Sidebar V1 group
header, and the chat header.
The color is stored server-side on project metadata (migration 039,
optional `color` on the project.meta.update command / meta-updated
event / project shells) so it syncs across devices, mirroring the
pinned-thread ordering precedent. A new `projectColor` capability flag
hides the picker for servers that predate it. Grouped projects share
one color across environments.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD
IAmJSDforce-pushed the t3code/add-repo-color-coding branch from 898f7f3 to 120e81cCompareAugust 30, 2026 16:54

@macroscopeappmacroscopeappBot 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.

Reviewed the web UI changes for shared-component, Tailwind ownership, and capability/environment-routing consistency. Two findings in apps/web/src/components/settings/ProjectSettingsPanel.tsx; the swatch/dot components themselves look consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx
- Group color now prefers the group representative's color over member
order, so a remote member can't override a colored primary checkout
(Macroscope, projectColors.ts).
- The chat header resolves the color through the same project grouping
as the sidebar, so a color set on another member of the logical
project still marks the thread (Macroscope + Cursor, ChatView).
- getCommandReadModel now maps projection_projects.color like the other
read-model builders (Macroscope, ProjectionSnapshotQuery).
- Palette CSS variables are literal var() strings owned by
projectColors.ts instead of runtime-built names, so Tailwind v4's
source scanner always emits them (Macroscope UI-consistency).
- Added unit tests for the color precedence and CSS value mapping.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR from Astrid Gealer's session.

Addressed the bot review feedback in f28c54d (after rebasing onto main in 120e81c, which also moved the color picker from the old SidebarV2 dialog into the new ProjectSettingsPanel and renumbered the migration to 044):

  • Group color precedence (Macroscope): resolveProjectGroupColor now takes the group and prefers the representative's color before falling back to the first colored member, so a remote member can no longer override a colored primary checkout. Covered by new unit tests in projectColors.test.ts.
  • Chat header ignores group color (Macroscope + Cursor): ChatView now resolves the header color through the same buildProjectGroups grouping the sidebar uses (resolveProjectColorInGroups), instead of reading only the physical project's own color.
  • getCommandReadModel omits color (Macroscope): now maps color: row.color like the other read-model builders.
  • Tailwind v4 variable emission (Macroscope UI-consistency): palette values are now a static PROJECT_COLOR_VALUES record of literal var(--color-*-500) strings owned by projectColors.ts, used by both the dots and the picker — no more runtime-built variable names depending on the unrelated color-selector.tsx for emission.
  • Stale-snapshot guard blocking color changes (Macroscope + Cursor): this code no longer exists after the rebase — the picker moved to the project settings page, where the no-op guard compares against the live group state rather than a dialog-open snapshot.

🤖 Generated with Claude Code

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f28c54d. Configure here.

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
…bing
- The project settings Color row now renders only when a member's server
advertises the projectColor capability, and the fan-out skips members
on pre-color servers — matching the contract comment and user docs
(Macroscope + Cursor).
- setProjectColor gets the same in-flight guard as setFaviconPath, and
the picker's disabled state is finally wired, so overlapping fan-outs
can't leave a group with mixed colors (Macroscope).
- getActiveProjectByWorkspaceRoot now copies row.color into the
OrchestrationProject it builds (Macroscope + Cursor).
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR.

Second round of bot feedback addressed in faf3e3f:

  • Capability gate (Macroscope UI-consistency + Cursor): the project settings Color row now renders only when at least one group member's server advertises the projectColor capability, and setProjectColor fans out only to capable members — pre-color servers are never sent the field, matching the contract comment and docs/user/project-colors.md.
  • In-flight guard (Macroscope): setProjectColor mirrors the adjacent setFaviconPath pattern (savingColorRef + isSavingColor), and the picker's previously-dead disabled prop is now wired, so two quick swatch clicks can't interleave fan-outs and leave the group with mixed colors.
  • getActiveProjectByWorkspaceRoot (Macroscope + Cursor): the hand-built OrchestrationProject now copies row.color, consistent with getSnapshot, getCommandReadModel, and mapProjectShellRow.

Validation: monorepo typecheck and lint clean; web suite 3013 passed; server projection/decider suites pass. The only failing server tests locally (bin.test.ts headless-connect and two ServerEnvironment.test.ts cases) reproduce identically on a clean upstream/main checkout on this machine — pre-existing environment issues, not from this PR.

🤖 Generated with Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@IAmJSD
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: color-code projects as an accessibility aid - #8772

Open
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding
Open

feat: color-code projects as an accessibility aid#8772
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding

Conversation

@IAmJSD

@IAmJSDIAmJSD commented Aug 30, 2026

Copy link
Copy Markdown

Note

This PR — code and description — was written by Claude Code (Claude Fable 5), working in Astrid Gealer's session at Infrawrench.

What

Adds the ability to color-code repos/projects as an accessibility feature, so they can be told apart at a glance. Pick a color from a nine-swatch palette (plus a "no color" option) in the sidebar's project actions dialog; it then shows as a small dot everywhere the project identifies itself:

  • sidebar thread cards and compact rows (V2), search results, and thread tooltips
  • the project filter menu and its trigger
  • the Sidebar V1 project group header
  • the chat header

How

Follows the precedent set by pinned-thread ordering (#5581) for server-synced per-entity state:

  • Contracts: optional ProjectColor field on OrchestrationProject(Shell), project.meta.update, and ProjectMetaUpdatedPayload — optional/nullable everywhere so old servers and clients interop. New projectColor capability flag so clients hide the picker instead of sending commands a pre-color server would reject.
  • Server: migration 039_ProjectionProjectsColor adds a color column to projection_projects; decider, in-memory projector, projection pipeline, and snapshot queries thread the field through.
  • Web: projectColors.ts (palette + group-color resolution) and ProjectColor.tsx (ProjectColorDot, ProjectColorPicker). Colors are persisted as palette names and rendered via Tailwind color tokens, so dots stay legible in both light and dark themes. Dots are aria-hidden (the project name is always present as text); picker swatches carry labels and aria-pressed state.
  • Grouped projects (same repo across environments) resolve to one color, and setting it in any environment colors the group.

Testing

  • New decider/projector tests (set / clear / leave-unchanged) and a persistence round-trip test.
  • Full monorepo typecheck and lint clean; web (1942), client-runtime (588), contracts (226), and server (1912) suites pass. The only server-suite failures are 6 pre-existing environment-dependent ones (service-launcher version mismatch on the dev box), identical on a clean tree.

Not included (possible follow-ups)

  • Mobile parity (mobile ProjectFavicon sites don't render dots yet).
  • Dots in the command palette / draft-hero project pickers.

🤖 Generated with Claude Code


Note

Medium Risk
Touches orchestration commands, a DB migration on projection_projects, and multi-environment fan-out in project settings; mitigated by optional wire fields and capability gating for version skew.

Overview
Adds optional project colors end to end so repos can be distinguished by a small colored dot in the sidebar, chat header, and project settings.

Contracts & server: Introduces ProjectColor and nullable color on project snapshots and project.meta.update / project.meta-updated (omitted when unchanged). Migration 044_ProjectionProjectsColor adds color to projection_projects; the decider, projector, SQL projections, and snapshot queries persist and expose it. Servers advertise a projectColor capability so older peers are not sent unknown fields.

Web: Palette helpers (projectColors.ts) plus ProjectColorDot / ProjectColorPicker. Settings fans color out to capability-aware group members; grouped logical projects share one resolved color across environments. Dots are decorative (aria-hidden); the picker is labeled for accessibility.

Tests & docs: Decider/projector and DB round-trip coverage, plus user docs for setting colors.

Reviewed by Cursor Bugbot for commit faf3e3f. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add end-to-end project color support as an accessibility aid

  • Introduces a nullable color field across OrchestrationProject, OrchestrationProjectShell, ProjectMetaUpdateCommand, and ProjectMetaUpdatedPayload in orchestration.ts, plus an optional projectColor capability flag in environment.ts
  • Adds migration 44 to add a color TEXT column to projection_projects in 044_ProjectionProjectsColor.ts; the projection pipeline, projector, and snapshot queries now persist and return color
  • The server advertises projectColor: true in ServerEnvironment.ts; the project settings UI in ProjectSettingsPanel.tsx only renders the new ProjectColorPicker when at least one group member is color-capable, and fans out color updates only to capable members
  • Sidebar, thread rows, tooltips, search results, draft rows, chat header, and legacy sidebar now display a ProjectColorDot using group-level color resolution via new utilities in projectColors.ts
  • Behavioral Change: project.meta-updated events now conditionally carry color (absent = unchanged, null = cleared); getSnapshot, getShellSnapshot, and getActiveProjectById responses now include color, which older clients may ignore under version skew. The capability flag gates the UI; servers not advertising projectColor will not show the picker.

Macroscope summarized faf3e3f.

@coderabbitai

coderabbitaiBot commented Aug 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 70ad8f0b-414a-4acb-9bca-9b5a87efd236

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 30, 2026
Comment threadapps/web/src/components/ChatView.tsx Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/projectColors.ts

@macroscopeappmacroscopeappBot 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.

One finding on the new web palette module. Everything else — capability gating and RPC both resolved from member.environmentId, activeProject scoped to the thread's environment, ProjectColorDot placements inside MenuRadioItem's children wrapper, and the raw swatch buttons (exempt as swatches) — looks consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/projectColors.ts Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/components/ChatView.tsx Outdated
@macroscopeapp

macroscopeappBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a persisted, cross-environment project-color capability with a new settings workflow and rendering across several production surfaces. Although it is opt-in and backward-compatible for uncolored projects, its cross-stack scope and multi-environment write behavior warrant human review.

You can add or adjust custom eligibility rules. Learn more.

Adds a per-project color, chosen from a theme-aware nine-swatch palette
in the sidebar's project actions dialog, shown as a small dot wherever
the project identifies itself: sidebar thread cards and compact rows,
search results, tooltips, the project filter menu, the Sidebar V1 group
header, and the chat header.
The color is stored server-side on project metadata (migration 039,
optional `color` on the project.meta.update command / meta-updated
event / project shells) so it syncs across devices, mirroring the
pinned-thread ordering precedent. A new `projectColor` capability flag
hides the picker for servers that predate it. Grouped projects share
one color across environments.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD
IAmJSDforce-pushed the t3code/add-repo-color-coding branch from 898f7f3 to 120e81cCompareAugust 30, 2026 16:54

@macroscopeappmacroscopeappBot 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.

Reviewed the web UI changes for shared-component, Tailwind ownership, and capability/environment-routing consistency. Two findings in apps/web/src/components/settings/ProjectSettingsPanel.tsx; the swatch/dot components themselves look consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx
- Group color now prefers the group representative's color over member
order, so a remote member can't override a colored primary checkout
(Macroscope, projectColors.ts).
- The chat header resolves the color through the same project grouping
as the sidebar, so a color set on another member of the logical
project still marks the thread (Macroscope + Cursor, ChatView).
- getCommandReadModel now maps projection_projects.color like the other
read-model builders (Macroscope, ProjectionSnapshotQuery).
- Palette CSS variables are literal var() strings owned by
projectColors.ts instead of runtime-built names, so Tailwind v4's
source scanner always emits them (Macroscope UI-consistency).
- Added unit tests for the color precedence and CSS value mapping.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR from Astrid Gealer's session.

Addressed the bot review feedback in f28c54d (after rebasing onto main in 120e81c, which also moved the color picker from the old SidebarV2 dialog into the new ProjectSettingsPanel and renumbered the migration to 044):

  • Group color precedence (Macroscope): resolveProjectGroupColor now takes the group and prefers the representative's color before falling back to the first colored member, so a remote member can no longer override a colored primary checkout. Covered by new unit tests in projectColors.test.ts.
  • Chat header ignores group color (Macroscope + Cursor): ChatView now resolves the header color through the same buildProjectGroups grouping the sidebar uses (resolveProjectColorInGroups), instead of reading only the physical project's own color.
  • getCommandReadModel omits color (Macroscope): now maps color: row.color like the other read-model builders.
  • Tailwind v4 variable emission (Macroscope UI-consistency): palette values are now a static PROJECT_COLOR_VALUES record of literal var(--color-*-500) strings owned by projectColors.ts, used by both the dots and the picker — no more runtime-built variable names depending on the unrelated color-selector.tsx for emission.
  • Stale-snapshot guard blocking color changes (Macroscope + Cursor): this code no longer exists after the rebase — the picker moved to the project settings page, where the no-op guard compares against the live group state rather than a dialog-open snapshot.

🤖 Generated with Claude Code

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f28c54d. Configure here.

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
…bing
- The project settings Color row now renders only when a member's server
advertises the projectColor capability, and the fan-out skips members
on pre-color servers — matching the contract comment and user docs
(Macroscope + Cursor).
- setProjectColor gets the same in-flight guard as setFaviconPath, and
the picker's disabled state is finally wired, so overlapping fan-outs
can't leave a group with mixed colors (Macroscope).
- getActiveProjectByWorkspaceRoot now copies row.color into the
OrchestrationProject it builds (Macroscope + Cursor).
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR.

Second round of bot feedback addressed in faf3e3f:

  • Capability gate (Macroscope UI-consistency + Cursor): the project settings Color row now renders only when at least one group member's server advertises the projectColor capability, and setProjectColor fans out only to capable members — pre-color servers are never sent the field, matching the contract comment and docs/user/project-colors.md.
  • In-flight guard (Macroscope): setProjectColor mirrors the adjacent setFaviconPath pattern (savingColorRef + isSavingColor), and the picker's previously-dead disabled prop is now wired, so two quick swatch clicks can't interleave fan-outs and leave the group with mixed colors.
  • getActiveProjectByWorkspaceRoot (Macroscope + Cursor): the hand-built OrchestrationProject now copies row.color, consistent with getSnapshot, getCommandReadModel, and mapProjectShellRow.

Validation: monorepo typecheck and lint clean; web suite 3013 passed; server projection/decider suites pass. The only failing server tests locally (bin.test.ts headless-connect and two ServerEnvironment.test.ts cases) reproduce identically on a clean upstream/main checkout on this machine — pre-existing environment issues, not from this PR.

🤖 Generated with Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@IAmJSD
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: color-code projects as an accessibility aid - #8772

Open
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding
Open

feat: color-code projects as an accessibility aid#8772
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding

Conversation

@IAmJSD

@IAmJSDIAmJSD commented Aug 30, 2026

Copy link
Copy Markdown

Note

This PR — code and description — was written by Claude Code (Claude Fable 5), working in Astrid Gealer's session at Infrawrench.

What

Adds the ability to color-code repos/projects as an accessibility feature, so they can be told apart at a glance. Pick a color from a nine-swatch palette (plus a "no color" option) in the sidebar's project actions dialog; it then shows as a small dot everywhere the project identifies itself:

  • sidebar thread cards and compact rows (V2), search results, and thread tooltips
  • the project filter menu and its trigger
  • the Sidebar V1 project group header
  • the chat header

How

Follows the precedent set by pinned-thread ordering (#5581) for server-synced per-entity state:

  • Contracts: optional ProjectColor field on OrchestrationProject(Shell), project.meta.update, and ProjectMetaUpdatedPayload — optional/nullable everywhere so old servers and clients interop. New projectColor capability flag so clients hide the picker instead of sending commands a pre-color server would reject.
  • Server: migration 039_ProjectionProjectsColor adds a color column to projection_projects; decider, in-memory projector, projection pipeline, and snapshot queries thread the field through.
  • Web: projectColors.ts (palette + group-color resolution) and ProjectColor.tsx (ProjectColorDot, ProjectColorPicker). Colors are persisted as palette names and rendered via Tailwind color tokens, so dots stay legible in both light and dark themes. Dots are aria-hidden (the project name is always present as text); picker swatches carry labels and aria-pressed state.
  • Grouped projects (same repo across environments) resolve to one color, and setting it in any environment colors the group.

Testing

  • New decider/projector tests (set / clear / leave-unchanged) and a persistence round-trip test.
  • Full monorepo typecheck and lint clean; web (1942), client-runtime (588), contracts (226), and server (1912) suites pass. The only server-suite failures are 6 pre-existing environment-dependent ones (service-launcher version mismatch on the dev box), identical on a clean tree.

Not included (possible follow-ups)

  • Mobile parity (mobile ProjectFavicon sites don't render dots yet).
  • Dots in the command palette / draft-hero project pickers.

🤖 Generated with Claude Code


Note

Medium Risk
Touches orchestration commands, a DB migration on projection_projects, and multi-environment fan-out in project settings; mitigated by optional wire fields and capability gating for version skew.

Overview
Adds optional project colors end to end so repos can be distinguished by a small colored dot in the sidebar, chat header, and project settings.

Contracts & server: Introduces ProjectColor and nullable color on project snapshots and project.meta.update / project.meta-updated (omitted when unchanged). Migration 044_ProjectionProjectsColor adds color to projection_projects; the decider, projector, SQL projections, and snapshot queries persist and expose it. Servers advertise a projectColor capability so older peers are not sent unknown fields.

Web: Palette helpers (projectColors.ts) plus ProjectColorDot / ProjectColorPicker. Settings fans color out to capability-aware group members; grouped logical projects share one resolved color across environments. Dots are decorative (aria-hidden); the picker is labeled for accessibility.

Tests & docs: Decider/projector and DB round-trip coverage, plus user docs for setting colors.

Reviewed by Cursor Bugbot for commit faf3e3f. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add end-to-end project color support as an accessibility aid

  • Introduces a nullable color field across OrchestrationProject, OrchestrationProjectShell, ProjectMetaUpdateCommand, and ProjectMetaUpdatedPayload in orchestration.ts, plus an optional projectColor capability flag in environment.ts
  • Adds migration 44 to add a color TEXT column to projection_projects in 044_ProjectionProjectsColor.ts; the projection pipeline, projector, and snapshot queries now persist and return color
  • The server advertises projectColor: true in ServerEnvironment.ts; the project settings UI in ProjectSettingsPanel.tsx only renders the new ProjectColorPicker when at least one group member is color-capable, and fans out color updates only to capable members
  • Sidebar, thread rows, tooltips, search results, draft rows, chat header, and legacy sidebar now display a ProjectColorDot using group-level color resolution via new utilities in projectColors.ts
  • Behavioral Change: project.meta-updated events now conditionally carry color (absent = unchanged, null = cleared); getSnapshot, getShellSnapshot, and getActiveProjectById responses now include color, which older clients may ignore under version skew. The capability flag gates the UI; servers not advertising projectColor will not show the picker.

Macroscope summarized faf3e3f.

@coderabbitai

coderabbitaiBot commented Aug 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 70ad8f0b-414a-4acb-9bca-9b5a87efd236

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 30, 2026
Comment threadapps/web/src/components/ChatView.tsx Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/projectColors.ts

@macroscopeappmacroscopeappBot 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.

One finding on the new web palette module. Everything else — capability gating and RPC both resolved from member.environmentId, activeProject scoped to the thread's environment, ProjectColorDot placements inside MenuRadioItem's children wrapper, and the raw swatch buttons (exempt as swatches) — looks consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/projectColors.ts Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/components/ChatView.tsx Outdated
@macroscopeapp

macroscopeappBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a persisted, cross-environment project-color capability with a new settings workflow and rendering across several production surfaces. Although it is opt-in and backward-compatible for uncolored projects, its cross-stack scope and multi-environment write behavior warrant human review.

You can add or adjust custom eligibility rules. Learn more.

Adds a per-project color, chosen from a theme-aware nine-swatch palette
in the sidebar's project actions dialog, shown as a small dot wherever
the project identifies itself: sidebar thread cards and compact rows,
search results, tooltips, the project filter menu, the Sidebar V1 group
header, and the chat header.
The color is stored server-side on project metadata (migration 039,
optional `color` on the project.meta.update command / meta-updated
event / project shells) so it syncs across devices, mirroring the
pinned-thread ordering precedent. A new `projectColor` capability flag
hides the picker for servers that predate it. Grouped projects share
one color across environments.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD
IAmJSDforce-pushed the t3code/add-repo-color-coding branch from 898f7f3 to 120e81cCompareAugust 30, 2026 16:54

@macroscopeappmacroscopeappBot 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.

Reviewed the web UI changes for shared-component, Tailwind ownership, and capability/environment-routing consistency. Two findings in apps/web/src/components/settings/ProjectSettingsPanel.tsx; the swatch/dot components themselves look consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx
- Group color now prefers the group representative's color over member
order, so a remote member can't override a colored primary checkout
(Macroscope, projectColors.ts).
- The chat header resolves the color through the same project grouping
as the sidebar, so a color set on another member of the logical
project still marks the thread (Macroscope + Cursor, ChatView).
- getCommandReadModel now maps projection_projects.color like the other
read-model builders (Macroscope, ProjectionSnapshotQuery).
- Palette CSS variables are literal var() strings owned by
projectColors.ts instead of runtime-built names, so Tailwind v4's
source scanner always emits them (Macroscope UI-consistency).
- Added unit tests for the color precedence and CSS value mapping.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR from Astrid Gealer's session.

Addressed the bot review feedback in f28c54d (after rebasing onto main in 120e81c, which also moved the color picker from the old SidebarV2 dialog into the new ProjectSettingsPanel and renumbered the migration to 044):

  • Group color precedence (Macroscope): resolveProjectGroupColor now takes the group and prefers the representative's color before falling back to the first colored member, so a remote member can no longer override a colored primary checkout. Covered by new unit tests in projectColors.test.ts.
  • Chat header ignores group color (Macroscope + Cursor): ChatView now resolves the header color through the same buildProjectGroups grouping the sidebar uses (resolveProjectColorInGroups), instead of reading only the physical project's own color.
  • getCommandReadModel omits color (Macroscope): now maps color: row.color like the other read-model builders.
  • Tailwind v4 variable emission (Macroscope UI-consistency): palette values are now a static PROJECT_COLOR_VALUES record of literal var(--color-*-500) strings owned by projectColors.ts, used by both the dots and the picker — no more runtime-built variable names depending on the unrelated color-selector.tsx for emission.
  • Stale-snapshot guard blocking color changes (Macroscope + Cursor): this code no longer exists after the rebase — the picker moved to the project settings page, where the no-op guard compares against the live group state rather than a dialog-open snapshot.

🤖 Generated with Claude Code

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f28c54d. Configure here.

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
…bing
- The project settings Color row now renders only when a member's server
advertises the projectColor capability, and the fan-out skips members
on pre-color servers — matching the contract comment and user docs
(Macroscope + Cursor).
- setProjectColor gets the same in-flight guard as setFaviconPath, and
the picker's disabled state is finally wired, so overlapping fan-outs
can't leave a group with mixed colors (Macroscope).
- getActiveProjectByWorkspaceRoot now copies row.color into the
OrchestrationProject it builds (Macroscope + Cursor).
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR.

Second round of bot feedback addressed in faf3e3f:

  • Capability gate (Macroscope UI-consistency + Cursor): the project settings Color row now renders only when at least one group member's server advertises the projectColor capability, and setProjectColor fans out only to capable members — pre-color servers are never sent the field, matching the contract comment and docs/user/project-colors.md.
  • In-flight guard (Macroscope): setProjectColor mirrors the adjacent setFaviconPath pattern (savingColorRef + isSavingColor), and the picker's previously-dead disabled prop is now wired, so two quick swatch clicks can't interleave fan-outs and leave the group with mixed colors.
  • getActiveProjectByWorkspaceRoot (Macroscope + Cursor): the hand-built OrchestrationProject now copies row.color, consistent with getSnapshot, getCommandReadModel, and mapProjectShellRow.

Validation: monorepo typecheck and lint clean; web suite 3013 passed; server projection/decider suites pass. The only failing server tests locally (bin.test.ts headless-connect and two ServerEnvironment.test.ts cases) reproduce identically on a clean upstream/main checkout on this machine — pre-existing environment issues, not from this PR.

🤖 Generated with Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@IAmJSD
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: color-code projects as an accessibility aid - #8772

Open
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding
Open

feat: color-code projects as an accessibility aid#8772
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding

Conversation

@IAmJSD

@IAmJSDIAmJSD commented Aug 30, 2026

Copy link
Copy Markdown

Note

This PR — code and description — was written by Claude Code (Claude Fable 5), working in Astrid Gealer's session at Infrawrench.

What

Adds the ability to color-code repos/projects as an accessibility feature, so they can be told apart at a glance. Pick a color from a nine-swatch palette (plus a "no color" option) in the sidebar's project actions dialog; it then shows as a small dot everywhere the project identifies itself:

  • sidebar thread cards and compact rows (V2), search results, and thread tooltips
  • the project filter menu and its trigger
  • the Sidebar V1 project group header
  • the chat header

How

Follows the precedent set by pinned-thread ordering (#5581) for server-synced per-entity state:

  • Contracts: optional ProjectColor field on OrchestrationProject(Shell), project.meta.update, and ProjectMetaUpdatedPayload — optional/nullable everywhere so old servers and clients interop. New projectColor capability flag so clients hide the picker instead of sending commands a pre-color server would reject.
  • Server: migration 039_ProjectionProjectsColor adds a color column to projection_projects; decider, in-memory projector, projection pipeline, and snapshot queries thread the field through.
  • Web: projectColors.ts (palette + group-color resolution) and ProjectColor.tsx (ProjectColorDot, ProjectColorPicker). Colors are persisted as palette names and rendered via Tailwind color tokens, so dots stay legible in both light and dark themes. Dots are aria-hidden (the project name is always present as text); picker swatches carry labels and aria-pressed state.
  • Grouped projects (same repo across environments) resolve to one color, and setting it in any environment colors the group.

Testing

  • New decider/projector tests (set / clear / leave-unchanged) and a persistence round-trip test.
  • Full monorepo typecheck and lint clean; web (1942), client-runtime (588), contracts (226), and server (1912) suites pass. The only server-suite failures are 6 pre-existing environment-dependent ones (service-launcher version mismatch on the dev box), identical on a clean tree.

Not included (possible follow-ups)

  • Mobile parity (mobile ProjectFavicon sites don't render dots yet).
  • Dots in the command palette / draft-hero project pickers.

🤖 Generated with Claude Code


Note

Medium Risk
Touches orchestration commands, a DB migration on projection_projects, and multi-environment fan-out in project settings; mitigated by optional wire fields and capability gating for version skew.

Overview
Adds optional project colors end to end so repos can be distinguished by a small colored dot in the sidebar, chat header, and project settings.

Contracts & server: Introduces ProjectColor and nullable color on project snapshots and project.meta.update / project.meta-updated (omitted when unchanged). Migration 044_ProjectionProjectsColor adds color to projection_projects; the decider, projector, SQL projections, and snapshot queries persist and expose it. Servers advertise a projectColor capability so older peers are not sent unknown fields.

Web: Palette helpers (projectColors.ts) plus ProjectColorDot / ProjectColorPicker. Settings fans color out to capability-aware group members; grouped logical projects share one resolved color across environments. Dots are decorative (aria-hidden); the picker is labeled for accessibility.

Tests & docs: Decider/projector and DB round-trip coverage, plus user docs for setting colors.

Reviewed by Cursor Bugbot for commit faf3e3f. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add end-to-end project color support as an accessibility aid

  • Introduces a nullable color field across OrchestrationProject, OrchestrationProjectShell, ProjectMetaUpdateCommand, and ProjectMetaUpdatedPayload in orchestration.ts, plus an optional projectColor capability flag in environment.ts
  • Adds migration 44 to add a color TEXT column to projection_projects in 044_ProjectionProjectsColor.ts; the projection pipeline, projector, and snapshot queries now persist and return color
  • The server advertises projectColor: true in ServerEnvironment.ts; the project settings UI in ProjectSettingsPanel.tsx only renders the new ProjectColorPicker when at least one group member is color-capable, and fans out color updates only to capable members
  • Sidebar, thread rows, tooltips, search results, draft rows, chat header, and legacy sidebar now display a ProjectColorDot using group-level color resolution via new utilities in projectColors.ts
  • Behavioral Change: project.meta-updated events now conditionally carry color (absent = unchanged, null = cleared); getSnapshot, getShellSnapshot, and getActiveProjectById responses now include color, which older clients may ignore under version skew. The capability flag gates the UI; servers not advertising projectColor will not show the picker.

Macroscope summarized faf3e3f.

@coderabbitai

coderabbitaiBot commented Aug 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 70ad8f0b-414a-4acb-9bca-9b5a87efd236

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 30, 2026
Comment threadapps/web/src/components/ChatView.tsx Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/projectColors.ts

@macroscopeappmacroscopeappBot 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.

One finding on the new web palette module. Everything else — capability gating and RPC both resolved from member.environmentId, activeProject scoped to the thread's environment, ProjectColorDot placements inside MenuRadioItem's children wrapper, and the raw swatch buttons (exempt as swatches) — looks consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/projectColors.ts Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/components/ChatView.tsx Outdated
@macroscopeapp

macroscopeappBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a persisted, cross-environment project-color capability with a new settings workflow and rendering across several production surfaces. Although it is opt-in and backward-compatible for uncolored projects, its cross-stack scope and multi-environment write behavior warrant human review.

You can add or adjust custom eligibility rules. Learn more.

Adds a per-project color, chosen from a theme-aware nine-swatch palette
in the sidebar's project actions dialog, shown as a small dot wherever
the project identifies itself: sidebar thread cards and compact rows,
search results, tooltips, the project filter menu, the Sidebar V1 group
header, and the chat header.
The color is stored server-side on project metadata (migration 039,
optional `color` on the project.meta.update command / meta-updated
event / project shells) so it syncs across devices, mirroring the
pinned-thread ordering precedent. A new `projectColor` capability flag
hides the picker for servers that predate it. Grouped projects share
one color across environments.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD
IAmJSDforce-pushed the t3code/add-repo-color-coding branch from 898f7f3 to 120e81cCompareAugust 30, 2026 16:54

@macroscopeappmacroscopeappBot 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.

Reviewed the web UI changes for shared-component, Tailwind ownership, and capability/environment-routing consistency. Two findings in apps/web/src/components/settings/ProjectSettingsPanel.tsx; the swatch/dot components themselves look consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx
- Group color now prefers the group representative's color over member
order, so a remote member can't override a colored primary checkout
(Macroscope, projectColors.ts).
- The chat header resolves the color through the same project grouping
as the sidebar, so a color set on another member of the logical
project still marks the thread (Macroscope + Cursor, ChatView).
- getCommandReadModel now maps projection_projects.color like the other
read-model builders (Macroscope, ProjectionSnapshotQuery).
- Palette CSS variables are literal var() strings owned by
projectColors.ts instead of runtime-built names, so Tailwind v4's
source scanner always emits them (Macroscope UI-consistency).
- Added unit tests for the color precedence and CSS value mapping.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR from Astrid Gealer's session.

Addressed the bot review feedback in f28c54d (after rebasing onto main in 120e81c, which also moved the color picker from the old SidebarV2 dialog into the new ProjectSettingsPanel and renumbered the migration to 044):

  • Group color precedence (Macroscope): resolveProjectGroupColor now takes the group and prefers the representative's color before falling back to the first colored member, so a remote member can no longer override a colored primary checkout. Covered by new unit tests in projectColors.test.ts.
  • Chat header ignores group color (Macroscope + Cursor): ChatView now resolves the header color through the same buildProjectGroups grouping the sidebar uses (resolveProjectColorInGroups), instead of reading only the physical project's own color.
  • getCommandReadModel omits color (Macroscope): now maps color: row.color like the other read-model builders.
  • Tailwind v4 variable emission (Macroscope UI-consistency): palette values are now a static PROJECT_COLOR_VALUES record of literal var(--color-*-500) strings owned by projectColors.ts, used by both the dots and the picker — no more runtime-built variable names depending on the unrelated color-selector.tsx for emission.
  • Stale-snapshot guard blocking color changes (Macroscope + Cursor): this code no longer exists after the rebase — the picker moved to the project settings page, where the no-op guard compares against the live group state rather than a dialog-open snapshot.

🤖 Generated with Claude Code

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f28c54d. Configure here.

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
…bing
- The project settings Color row now renders only when a member's server
advertises the projectColor capability, and the fan-out skips members
on pre-color servers — matching the contract comment and user docs
(Macroscope + Cursor).
- setProjectColor gets the same in-flight guard as setFaviconPath, and
the picker's disabled state is finally wired, so overlapping fan-outs
can't leave a group with mixed colors (Macroscope).
- getActiveProjectByWorkspaceRoot now copies row.color into the
OrchestrationProject it builds (Macroscope + Cursor).
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR.

Second round of bot feedback addressed in faf3e3f:

  • Capability gate (Macroscope UI-consistency + Cursor): the project settings Color row now renders only when at least one group member's server advertises the projectColor capability, and setProjectColor fans out only to capable members — pre-color servers are never sent the field, matching the contract comment and docs/user/project-colors.md.
  • In-flight guard (Macroscope): setProjectColor mirrors the adjacent setFaviconPath pattern (savingColorRef + isSavingColor), and the picker's previously-dead disabled prop is now wired, so two quick swatch clicks can't interleave fan-outs and leave the group with mixed colors.
  • getActiveProjectByWorkspaceRoot (Macroscope + Cursor): the hand-built OrchestrationProject now copies row.color, consistent with getSnapshot, getCommandReadModel, and mapProjectShellRow.

Validation: monorepo typecheck and lint clean; web suite 3013 passed; server projection/decider suites pass. The only failing server tests locally (bin.test.ts headless-connect and two ServerEnvironment.test.ts cases) reproduce identically on a clean upstream/main checkout on this machine — pre-existing environment issues, not from this PR.

🤖 Generated with Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@IAmJSD
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: color-code projects as an accessibility aid - #8772

Open
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding
Open

feat: color-code projects as an accessibility aid#8772
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding

Conversation

@IAmJSD

@IAmJSDIAmJSD commented Aug 30, 2026

Copy link
Copy Markdown

Note

This PR — code and description — was written by Claude Code (Claude Fable 5), working in Astrid Gealer's session at Infrawrench.

What

Adds the ability to color-code repos/projects as an accessibility feature, so they can be told apart at a glance. Pick a color from a nine-swatch palette (plus a "no color" option) in the sidebar's project actions dialog; it then shows as a small dot everywhere the project identifies itself:

  • sidebar thread cards and compact rows (V2), search results, and thread tooltips
  • the project filter menu and its trigger
  • the Sidebar V1 project group header
  • the chat header

How

Follows the precedent set by pinned-thread ordering (#5581) for server-synced per-entity state:

  • Contracts: optional ProjectColor field on OrchestrationProject(Shell), project.meta.update, and ProjectMetaUpdatedPayload — optional/nullable everywhere so old servers and clients interop. New projectColor capability flag so clients hide the picker instead of sending commands a pre-color server would reject.
  • Server: migration 039_ProjectionProjectsColor adds a color column to projection_projects; decider, in-memory projector, projection pipeline, and snapshot queries thread the field through.
  • Web: projectColors.ts (palette + group-color resolution) and ProjectColor.tsx (ProjectColorDot, ProjectColorPicker). Colors are persisted as palette names and rendered via Tailwind color tokens, so dots stay legible in both light and dark themes. Dots are aria-hidden (the project name is always present as text); picker swatches carry labels and aria-pressed state.
  • Grouped projects (same repo across environments) resolve to one color, and setting it in any environment colors the group.

Testing

  • New decider/projector tests (set / clear / leave-unchanged) and a persistence round-trip test.
  • Full monorepo typecheck and lint clean; web (1942), client-runtime (588), contracts (226), and server (1912) suites pass. The only server-suite failures are 6 pre-existing environment-dependent ones (service-launcher version mismatch on the dev box), identical on a clean tree.

Not included (possible follow-ups)

  • Mobile parity (mobile ProjectFavicon sites don't render dots yet).
  • Dots in the command palette / draft-hero project pickers.

🤖 Generated with Claude Code


Note

Medium Risk
Touches orchestration commands, a DB migration on projection_projects, and multi-environment fan-out in project settings; mitigated by optional wire fields and capability gating for version skew.

Overview
Adds optional project colors end to end so repos can be distinguished by a small colored dot in the sidebar, chat header, and project settings.

Contracts & server: Introduces ProjectColor and nullable color on project snapshots and project.meta.update / project.meta-updated (omitted when unchanged). Migration 044_ProjectionProjectsColor adds color to projection_projects; the decider, projector, SQL projections, and snapshot queries persist and expose it. Servers advertise a projectColor capability so older peers are not sent unknown fields.

Web: Palette helpers (projectColors.ts) plus ProjectColorDot / ProjectColorPicker. Settings fans color out to capability-aware group members; grouped logical projects share one resolved color across environments. Dots are decorative (aria-hidden); the picker is labeled for accessibility.

Tests & docs: Decider/projector and DB round-trip coverage, plus user docs for setting colors.

Reviewed by Cursor Bugbot for commit faf3e3f. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add end-to-end project color support as an accessibility aid

  • Introduces a nullable color field across OrchestrationProject, OrchestrationProjectShell, ProjectMetaUpdateCommand, and ProjectMetaUpdatedPayload in orchestration.ts, plus an optional projectColor capability flag in environment.ts
  • Adds migration 44 to add a color TEXT column to projection_projects in 044_ProjectionProjectsColor.ts; the projection pipeline, projector, and snapshot queries now persist and return color
  • The server advertises projectColor: true in ServerEnvironment.ts; the project settings UI in ProjectSettingsPanel.tsx only renders the new ProjectColorPicker when at least one group member is color-capable, and fans out color updates only to capable members
  • Sidebar, thread rows, tooltips, search results, draft rows, chat header, and legacy sidebar now display a ProjectColorDot using group-level color resolution via new utilities in projectColors.ts
  • Behavioral Change: project.meta-updated events now conditionally carry color (absent = unchanged, null = cleared); getSnapshot, getShellSnapshot, and getActiveProjectById responses now include color, which older clients may ignore under version skew. The capability flag gates the UI; servers not advertising projectColor will not show the picker.

Macroscope summarized faf3e3f.

@coderabbitai

coderabbitaiBot commented Aug 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 70ad8f0b-414a-4acb-9bca-9b5a87efd236

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 30, 2026
Comment threadapps/web/src/components/ChatView.tsx Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/projectColors.ts

@macroscopeappmacroscopeappBot 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.

One finding on the new web palette module. Everything else — capability gating and RPC both resolved from member.environmentId, activeProject scoped to the thread's environment, ProjectColorDot placements inside MenuRadioItem's children wrapper, and the raw swatch buttons (exempt as swatches) — looks consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/projectColors.ts Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/components/ChatView.tsx Outdated
@macroscopeapp

macroscopeappBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a persisted, cross-environment project-color capability with a new settings workflow and rendering across several production surfaces. Although it is opt-in and backward-compatible for uncolored projects, its cross-stack scope and multi-environment write behavior warrant human review.

You can add or adjust custom eligibility rules. Learn more.

Adds a per-project color, chosen from a theme-aware nine-swatch palette
in the sidebar's project actions dialog, shown as a small dot wherever
the project identifies itself: sidebar thread cards and compact rows,
search results, tooltips, the project filter menu, the Sidebar V1 group
header, and the chat header.
The color is stored server-side on project metadata (migration 039,
optional `color` on the project.meta.update command / meta-updated
event / project shells) so it syncs across devices, mirroring the
pinned-thread ordering precedent. A new `projectColor` capability flag
hides the picker for servers that predate it. Grouped projects share
one color across environments.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD
IAmJSDforce-pushed the t3code/add-repo-color-coding branch from 898f7f3 to 120e81cCompareAugust 30, 2026 16:54

@macroscopeappmacroscopeappBot 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.

Reviewed the web UI changes for shared-component, Tailwind ownership, and capability/environment-routing consistency. Two findings in apps/web/src/components/settings/ProjectSettingsPanel.tsx; the swatch/dot components themselves look consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx
- Group color now prefers the group representative's color over member
order, so a remote member can't override a colored primary checkout
(Macroscope, projectColors.ts).
- The chat header resolves the color through the same project grouping
as the sidebar, so a color set on another member of the logical
project still marks the thread (Macroscope + Cursor, ChatView).
- getCommandReadModel now maps projection_projects.color like the other
read-model builders (Macroscope, ProjectionSnapshotQuery).
- Palette CSS variables are literal var() strings owned by
projectColors.ts instead of runtime-built names, so Tailwind v4's
source scanner always emits them (Macroscope UI-consistency).
- Added unit tests for the color precedence and CSS value mapping.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR from Astrid Gealer's session.

Addressed the bot review feedback in f28c54d (after rebasing onto main in 120e81c, which also moved the color picker from the old SidebarV2 dialog into the new ProjectSettingsPanel and renumbered the migration to 044):

  • Group color precedence (Macroscope): resolveProjectGroupColor now takes the group and prefers the representative's color before falling back to the first colored member, so a remote member can no longer override a colored primary checkout. Covered by new unit tests in projectColors.test.ts.
  • Chat header ignores group color (Macroscope + Cursor): ChatView now resolves the header color through the same buildProjectGroups grouping the sidebar uses (resolveProjectColorInGroups), instead of reading only the physical project's own color.
  • getCommandReadModel omits color (Macroscope): now maps color: row.color like the other read-model builders.
  • Tailwind v4 variable emission (Macroscope UI-consistency): palette values are now a static PROJECT_COLOR_VALUES record of literal var(--color-*-500) strings owned by projectColors.ts, used by both the dots and the picker — no more runtime-built variable names depending on the unrelated color-selector.tsx for emission.
  • Stale-snapshot guard blocking color changes (Macroscope + Cursor): this code no longer exists after the rebase — the picker moved to the project settings page, where the no-op guard compares against the live group state rather than a dialog-open snapshot.

🤖 Generated with Claude Code

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f28c54d. Configure here.

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
…bing
- The project settings Color row now renders only when a member's server
advertises the projectColor capability, and the fan-out skips members
on pre-color servers — matching the contract comment and user docs
(Macroscope + Cursor).
- setProjectColor gets the same in-flight guard as setFaviconPath, and
the picker's disabled state is finally wired, so overlapping fan-outs
can't leave a group with mixed colors (Macroscope).
- getActiveProjectByWorkspaceRoot now copies row.color into the
OrchestrationProject it builds (Macroscope + Cursor).
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR.

Second round of bot feedback addressed in faf3e3f:

  • Capability gate (Macroscope UI-consistency + Cursor): the project settings Color row now renders only when at least one group member's server advertises the projectColor capability, and setProjectColor fans out only to capable members — pre-color servers are never sent the field, matching the contract comment and docs/user/project-colors.md.
  • In-flight guard (Macroscope): setProjectColor mirrors the adjacent setFaviconPath pattern (savingColorRef + isSavingColor), and the picker's previously-dead disabled prop is now wired, so two quick swatch clicks can't interleave fan-outs and leave the group with mixed colors.
  • getActiveProjectByWorkspaceRoot (Macroscope + Cursor): the hand-built OrchestrationProject now copies row.color, consistent with getSnapshot, getCommandReadModel, and mapProjectShellRow.

Validation: monorepo typecheck and lint clean; web suite 3013 passed; server projection/decider suites pass. The only failing server tests locally (bin.test.ts headless-connect and two ServerEnvironment.test.ts cases) reproduce identically on a clean upstream/main checkout on this machine — pre-existing environment issues, not from this PR.

🤖 Generated with Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@IAmJSD
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: color-code projects as an accessibility aid - #8772

Open
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding
Open

feat: color-code projects as an accessibility aid#8772
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding

Conversation

@IAmJSD

@IAmJSDIAmJSD commented Aug 30, 2026

Copy link
Copy Markdown

Note

This PR — code and description — was written by Claude Code (Claude Fable 5), working in Astrid Gealer's session at Infrawrench.

What

Adds the ability to color-code repos/projects as an accessibility feature, so they can be told apart at a glance. Pick a color from a nine-swatch palette (plus a "no color" option) in the sidebar's project actions dialog; it then shows as a small dot everywhere the project identifies itself:

  • sidebar thread cards and compact rows (V2), search results, and thread tooltips
  • the project filter menu and its trigger
  • the Sidebar V1 project group header
  • the chat header

How

Follows the precedent set by pinned-thread ordering (#5581) for server-synced per-entity state:

  • Contracts: optional ProjectColor field on OrchestrationProject(Shell), project.meta.update, and ProjectMetaUpdatedPayload — optional/nullable everywhere so old servers and clients interop. New projectColor capability flag so clients hide the picker instead of sending commands a pre-color server would reject.
  • Server: migration 039_ProjectionProjectsColor adds a color column to projection_projects; decider, in-memory projector, projection pipeline, and snapshot queries thread the field through.
  • Web: projectColors.ts (palette + group-color resolution) and ProjectColor.tsx (ProjectColorDot, ProjectColorPicker). Colors are persisted as palette names and rendered via Tailwind color tokens, so dots stay legible in both light and dark themes. Dots are aria-hidden (the project name is always present as text); picker swatches carry labels and aria-pressed state.
  • Grouped projects (same repo across environments) resolve to one color, and setting it in any environment colors the group.

Testing

  • New decider/projector tests (set / clear / leave-unchanged) and a persistence round-trip test.
  • Full monorepo typecheck and lint clean; web (1942), client-runtime (588), contracts (226), and server (1912) suites pass. The only server-suite failures are 6 pre-existing environment-dependent ones (service-launcher version mismatch on the dev box), identical on a clean tree.

Not included (possible follow-ups)

  • Mobile parity (mobile ProjectFavicon sites don't render dots yet).
  • Dots in the command palette / draft-hero project pickers.

🤖 Generated with Claude Code


Note

Medium Risk
Touches orchestration commands, a DB migration on projection_projects, and multi-environment fan-out in project settings; mitigated by optional wire fields and capability gating for version skew.

Overview
Adds optional project colors end to end so repos can be distinguished by a small colored dot in the sidebar, chat header, and project settings.

Contracts & server: Introduces ProjectColor and nullable color on project snapshots and project.meta.update / project.meta-updated (omitted when unchanged). Migration 044_ProjectionProjectsColor adds color to projection_projects; the decider, projector, SQL projections, and snapshot queries persist and expose it. Servers advertise a projectColor capability so older peers are not sent unknown fields.

Web: Palette helpers (projectColors.ts) plus ProjectColorDot / ProjectColorPicker. Settings fans color out to capability-aware group members; grouped logical projects share one resolved color across environments. Dots are decorative (aria-hidden); the picker is labeled for accessibility.

Tests & docs: Decider/projector and DB round-trip coverage, plus user docs for setting colors.

Reviewed by Cursor Bugbot for commit faf3e3f. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add end-to-end project color support as an accessibility aid

  • Introduces a nullable color field across OrchestrationProject, OrchestrationProjectShell, ProjectMetaUpdateCommand, and ProjectMetaUpdatedPayload in orchestration.ts, plus an optional projectColor capability flag in environment.ts
  • Adds migration 44 to add a color TEXT column to projection_projects in 044_ProjectionProjectsColor.ts; the projection pipeline, projector, and snapshot queries now persist and return color
  • The server advertises projectColor: true in ServerEnvironment.ts; the project settings UI in ProjectSettingsPanel.tsx only renders the new ProjectColorPicker when at least one group member is color-capable, and fans out color updates only to capable members
  • Sidebar, thread rows, tooltips, search results, draft rows, chat header, and legacy sidebar now display a ProjectColorDot using group-level color resolution via new utilities in projectColors.ts
  • Behavioral Change: project.meta-updated events now conditionally carry color (absent = unchanged, null = cleared); getSnapshot, getShellSnapshot, and getActiveProjectById responses now include color, which older clients may ignore under version skew. The capability flag gates the UI; servers not advertising projectColor will not show the picker.

Macroscope summarized faf3e3f.

@coderabbitai

coderabbitaiBot commented Aug 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 70ad8f0b-414a-4acb-9bca-9b5a87efd236

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 30, 2026
Comment threadapps/web/src/components/ChatView.tsx Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/projectColors.ts

@macroscopeappmacroscopeappBot 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.

One finding on the new web palette module. Everything else — capability gating and RPC both resolved from member.environmentId, activeProject scoped to the thread's environment, ProjectColorDot placements inside MenuRadioItem's children wrapper, and the raw swatch buttons (exempt as swatches) — looks consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/projectColors.ts Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/components/ChatView.tsx Outdated
@macroscopeapp

macroscopeappBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a persisted, cross-environment project-color capability with a new settings workflow and rendering across several production surfaces. Although it is opt-in and backward-compatible for uncolored projects, its cross-stack scope and multi-environment write behavior warrant human review.

You can add or adjust custom eligibility rules. Learn more.

Adds a per-project color, chosen from a theme-aware nine-swatch palette
in the sidebar's project actions dialog, shown as a small dot wherever
the project identifies itself: sidebar thread cards and compact rows,
search results, tooltips, the project filter menu, the Sidebar V1 group
header, and the chat header.
The color is stored server-side on project metadata (migration 039,
optional `color` on the project.meta.update command / meta-updated
event / project shells) so it syncs across devices, mirroring the
pinned-thread ordering precedent. A new `projectColor` capability flag
hides the picker for servers that predate it. Grouped projects share
one color across environments.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD
IAmJSDforce-pushed the t3code/add-repo-color-coding branch from 898f7f3 to 120e81cCompareAugust 30, 2026 16:54

@macroscopeappmacroscopeappBot 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.

Reviewed the web UI changes for shared-component, Tailwind ownership, and capability/environment-routing consistency. Two findings in apps/web/src/components/settings/ProjectSettingsPanel.tsx; the swatch/dot components themselves look consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx
- Group color now prefers the group representative's color over member
order, so a remote member can't override a colored primary checkout
(Macroscope, projectColors.ts).
- The chat header resolves the color through the same project grouping
as the sidebar, so a color set on another member of the logical
project still marks the thread (Macroscope + Cursor, ChatView).
- getCommandReadModel now maps projection_projects.color like the other
read-model builders (Macroscope, ProjectionSnapshotQuery).
- Palette CSS variables are literal var() strings owned by
projectColors.ts instead of runtime-built names, so Tailwind v4's
source scanner always emits them (Macroscope UI-consistency).
- Added unit tests for the color precedence and CSS value mapping.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR from Astrid Gealer's session.

Addressed the bot review feedback in f28c54d (after rebasing onto main in 120e81c, which also moved the color picker from the old SidebarV2 dialog into the new ProjectSettingsPanel and renumbered the migration to 044):

  • Group color precedence (Macroscope): resolveProjectGroupColor now takes the group and prefers the representative's color before falling back to the first colored member, so a remote member can no longer override a colored primary checkout. Covered by new unit tests in projectColors.test.ts.
  • Chat header ignores group color (Macroscope + Cursor): ChatView now resolves the header color through the same buildProjectGroups grouping the sidebar uses (resolveProjectColorInGroups), instead of reading only the physical project's own color.
  • getCommandReadModel omits color (Macroscope): now maps color: row.color like the other read-model builders.
  • Tailwind v4 variable emission (Macroscope UI-consistency): palette values are now a static PROJECT_COLOR_VALUES record of literal var(--color-*-500) strings owned by projectColors.ts, used by both the dots and the picker — no more runtime-built variable names depending on the unrelated color-selector.tsx for emission.
  • Stale-snapshot guard blocking color changes (Macroscope + Cursor): this code no longer exists after the rebase — the picker moved to the project settings page, where the no-op guard compares against the live group state rather than a dialog-open snapshot.

🤖 Generated with Claude Code

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f28c54d. Configure here.

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
…bing
- The project settings Color row now renders only when a member's server
advertises the projectColor capability, and the fan-out skips members
on pre-color servers — matching the contract comment and user docs
(Macroscope + Cursor).
- setProjectColor gets the same in-flight guard as setFaviconPath, and
the picker's disabled state is finally wired, so overlapping fan-outs
can't leave a group with mixed colors (Macroscope).
- getActiveProjectByWorkspaceRoot now copies row.color into the
OrchestrationProject it builds (Macroscope + Cursor).
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR.

Second round of bot feedback addressed in faf3e3f:

  • Capability gate (Macroscope UI-consistency + Cursor): the project settings Color row now renders only when at least one group member's server advertises the projectColor capability, and setProjectColor fans out only to capable members — pre-color servers are never sent the field, matching the contract comment and docs/user/project-colors.md.
  • In-flight guard (Macroscope): setProjectColor mirrors the adjacent setFaviconPath pattern (savingColorRef + isSavingColor), and the picker's previously-dead disabled prop is now wired, so two quick swatch clicks can't interleave fan-outs and leave the group with mixed colors.
  • getActiveProjectByWorkspaceRoot (Macroscope + Cursor): the hand-built OrchestrationProject now copies row.color, consistent with getSnapshot, getCommandReadModel, and mapProjectShellRow.

Validation: monorepo typecheck and lint clean; web suite 3013 passed; server projection/decider suites pass. The only failing server tests locally (bin.test.ts headless-connect and two ServerEnvironment.test.ts cases) reproduce identically on a clean upstream/main checkout on this machine — pre-existing environment issues, not from this PR.

🤖 Generated with Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@IAmJSD
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: color-code projects as an accessibility aid - #8772

Open
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding
Open

feat: color-code projects as an accessibility aid#8772
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding

Conversation

@IAmJSD

@IAmJSDIAmJSD commented Aug 30, 2026

Copy link
Copy Markdown

Note

This PR — code and description — was written by Claude Code (Claude Fable 5), working in Astrid Gealer's session at Infrawrench.

What

Adds the ability to color-code repos/projects as an accessibility feature, so they can be told apart at a glance. Pick a color from a nine-swatch palette (plus a "no color" option) in the sidebar's project actions dialog; it then shows as a small dot everywhere the project identifies itself:

  • sidebar thread cards and compact rows (V2), search results, and thread tooltips
  • the project filter menu and its trigger
  • the Sidebar V1 project group header
  • the chat header

How

Follows the precedent set by pinned-thread ordering (#5581) for server-synced per-entity state:

  • Contracts: optional ProjectColor field on OrchestrationProject(Shell), project.meta.update, and ProjectMetaUpdatedPayload — optional/nullable everywhere so old servers and clients interop. New projectColor capability flag so clients hide the picker instead of sending commands a pre-color server would reject.
  • Server: migration 039_ProjectionProjectsColor adds a color column to projection_projects; decider, in-memory projector, projection pipeline, and snapshot queries thread the field through.
  • Web: projectColors.ts (palette + group-color resolution) and ProjectColor.tsx (ProjectColorDot, ProjectColorPicker). Colors are persisted as palette names and rendered via Tailwind color tokens, so dots stay legible in both light and dark themes. Dots are aria-hidden (the project name is always present as text); picker swatches carry labels and aria-pressed state.
  • Grouped projects (same repo across environments) resolve to one color, and setting it in any environment colors the group.

Testing

  • New decider/projector tests (set / clear / leave-unchanged) and a persistence round-trip test.
  • Full monorepo typecheck and lint clean; web (1942), client-runtime (588), contracts (226), and server (1912) suites pass. The only server-suite failures are 6 pre-existing environment-dependent ones (service-launcher version mismatch on the dev box), identical on a clean tree.

Not included (possible follow-ups)

  • Mobile parity (mobile ProjectFavicon sites don't render dots yet).
  • Dots in the command palette / draft-hero project pickers.

🤖 Generated with Claude Code


Note

Medium Risk
Touches orchestration commands, a DB migration on projection_projects, and multi-environment fan-out in project settings; mitigated by optional wire fields and capability gating for version skew.

Overview
Adds optional project colors end to end so repos can be distinguished by a small colored dot in the sidebar, chat header, and project settings.

Contracts & server: Introduces ProjectColor and nullable color on project snapshots and project.meta.update / project.meta-updated (omitted when unchanged). Migration 044_ProjectionProjectsColor adds color to projection_projects; the decider, projector, SQL projections, and snapshot queries persist and expose it. Servers advertise a projectColor capability so older peers are not sent unknown fields.

Web: Palette helpers (projectColors.ts) plus ProjectColorDot / ProjectColorPicker. Settings fans color out to capability-aware group members; grouped logical projects share one resolved color across environments. Dots are decorative (aria-hidden); the picker is labeled for accessibility.

Tests & docs: Decider/projector and DB round-trip coverage, plus user docs for setting colors.

Reviewed by Cursor Bugbot for commit faf3e3f. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add end-to-end project color support as an accessibility aid

  • Introduces a nullable color field across OrchestrationProject, OrchestrationProjectShell, ProjectMetaUpdateCommand, and ProjectMetaUpdatedPayload in orchestration.ts, plus an optional projectColor capability flag in environment.ts
  • Adds migration 44 to add a color TEXT column to projection_projects in 044_ProjectionProjectsColor.ts; the projection pipeline, projector, and snapshot queries now persist and return color
  • The server advertises projectColor: true in ServerEnvironment.ts; the project settings UI in ProjectSettingsPanel.tsx only renders the new ProjectColorPicker when at least one group member is color-capable, and fans out color updates only to capable members
  • Sidebar, thread rows, tooltips, search results, draft rows, chat header, and legacy sidebar now display a ProjectColorDot using group-level color resolution via new utilities in projectColors.ts
  • Behavioral Change: project.meta-updated events now conditionally carry color (absent = unchanged, null = cleared); getSnapshot, getShellSnapshot, and getActiveProjectById responses now include color, which older clients may ignore under version skew. The capability flag gates the UI; servers not advertising projectColor will not show the picker.

Macroscope summarized faf3e3f.

@coderabbitai

coderabbitaiBot commented Aug 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 70ad8f0b-414a-4acb-9bca-9b5a87efd236

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 30, 2026
Comment threadapps/web/src/components/ChatView.tsx Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/projectColors.ts

@macroscopeappmacroscopeappBot 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.

One finding on the new web palette module. Everything else — capability gating and RPC both resolved from member.environmentId, activeProject scoped to the thread's environment, ProjectColorDot placements inside MenuRadioItem's children wrapper, and the raw swatch buttons (exempt as swatches) — looks consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/projectColors.ts Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/components/ChatView.tsx Outdated
@macroscopeapp

macroscopeappBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a persisted, cross-environment project-color capability with a new settings workflow and rendering across several production surfaces. Although it is opt-in and backward-compatible for uncolored projects, its cross-stack scope and multi-environment write behavior warrant human review.

You can add or adjust custom eligibility rules. Learn more.

Adds a per-project color, chosen from a theme-aware nine-swatch palette
in the sidebar's project actions dialog, shown as a small dot wherever
the project identifies itself: sidebar thread cards and compact rows,
search results, tooltips, the project filter menu, the Sidebar V1 group
header, and the chat header.
The color is stored server-side on project metadata (migration 039,
optional `color` on the project.meta.update command / meta-updated
event / project shells) so it syncs across devices, mirroring the
pinned-thread ordering precedent. A new `projectColor` capability flag
hides the picker for servers that predate it. Grouped projects share
one color across environments.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD
IAmJSDforce-pushed the t3code/add-repo-color-coding branch from 898f7f3 to 120e81cCompareAugust 30, 2026 16:54

@macroscopeappmacroscopeappBot 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.

Reviewed the web UI changes for shared-component, Tailwind ownership, and capability/environment-routing consistency. Two findings in apps/web/src/components/settings/ProjectSettingsPanel.tsx; the swatch/dot components themselves look consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx
- Group color now prefers the group representative's color over member
order, so a remote member can't override a colored primary checkout
(Macroscope, projectColors.ts).
- The chat header resolves the color through the same project grouping
as the sidebar, so a color set on another member of the logical
project still marks the thread (Macroscope + Cursor, ChatView).
- getCommandReadModel now maps projection_projects.color like the other
read-model builders (Macroscope, ProjectionSnapshotQuery).
- Palette CSS variables are literal var() strings owned by
projectColors.ts instead of runtime-built names, so Tailwind v4's
source scanner always emits them (Macroscope UI-consistency).
- Added unit tests for the color precedence and CSS value mapping.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR from Astrid Gealer's session.

Addressed the bot review feedback in f28c54d (after rebasing onto main in 120e81c, which also moved the color picker from the old SidebarV2 dialog into the new ProjectSettingsPanel and renumbered the migration to 044):

  • Group color precedence (Macroscope): resolveProjectGroupColor now takes the group and prefers the representative's color before falling back to the first colored member, so a remote member can no longer override a colored primary checkout. Covered by new unit tests in projectColors.test.ts.
  • Chat header ignores group color (Macroscope + Cursor): ChatView now resolves the header color through the same buildProjectGroups grouping the sidebar uses (resolveProjectColorInGroups), instead of reading only the physical project's own color.
  • getCommandReadModel omits color (Macroscope): now maps color: row.color like the other read-model builders.
  • Tailwind v4 variable emission (Macroscope UI-consistency): palette values are now a static PROJECT_COLOR_VALUES record of literal var(--color-*-500) strings owned by projectColors.ts, used by both the dots and the picker — no more runtime-built variable names depending on the unrelated color-selector.tsx for emission.
  • Stale-snapshot guard blocking color changes (Macroscope + Cursor): this code no longer exists after the rebase — the picker moved to the project settings page, where the no-op guard compares against the live group state rather than a dialog-open snapshot.

🤖 Generated with Claude Code

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f28c54d. Configure here.

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
…bing
- The project settings Color row now renders only when a member's server
advertises the projectColor capability, and the fan-out skips members
on pre-color servers — matching the contract comment and user docs
(Macroscope + Cursor).
- setProjectColor gets the same in-flight guard as setFaviconPath, and
the picker's disabled state is finally wired, so overlapping fan-outs
can't leave a group with mixed colors (Macroscope).
- getActiveProjectByWorkspaceRoot now copies row.color into the
OrchestrationProject it builds (Macroscope + Cursor).
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR.

Second round of bot feedback addressed in faf3e3f:

  • Capability gate (Macroscope UI-consistency + Cursor): the project settings Color row now renders only when at least one group member's server advertises the projectColor capability, and setProjectColor fans out only to capable members — pre-color servers are never sent the field, matching the contract comment and docs/user/project-colors.md.
  • In-flight guard (Macroscope): setProjectColor mirrors the adjacent setFaviconPath pattern (savingColorRef + isSavingColor), and the picker's previously-dead disabled prop is now wired, so two quick swatch clicks can't interleave fan-outs and leave the group with mixed colors.
  • getActiveProjectByWorkspaceRoot (Macroscope + Cursor): the hand-built OrchestrationProject now copies row.color, consistent with getSnapshot, getCommandReadModel, and mapProjectShellRow.

Validation: monorepo typecheck and lint clean; web suite 3013 passed; server projection/decider suites pass. The only failing server tests locally (bin.test.ts headless-connect and two ServerEnvironment.test.ts cases) reproduce identically on a clean upstream/main checkout on this machine — pre-existing environment issues, not from this PR.

🤖 Generated with Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@IAmJSD
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: color-code projects as an accessibility aid - #8772

Open
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding
Open

feat: color-code projects as an accessibility aid#8772
IAmJSD wants to merge 3 commits into
pingdotgg:mainfrom
Infrawrench:t3code/add-repo-color-coding

Conversation

@IAmJSD

@IAmJSDIAmJSD commented Aug 30, 2026

Copy link
Copy Markdown

Note

This PR — code and description — was written by Claude Code (Claude Fable 5), working in Astrid Gealer's session at Infrawrench.

What

Adds the ability to color-code repos/projects as an accessibility feature, so they can be told apart at a glance. Pick a color from a nine-swatch palette (plus a "no color" option) in the sidebar's project actions dialog; it then shows as a small dot everywhere the project identifies itself:

  • sidebar thread cards and compact rows (V2), search results, and thread tooltips
  • the project filter menu and its trigger
  • the Sidebar V1 project group header
  • the chat header

How

Follows the precedent set by pinned-thread ordering (#5581) for server-synced per-entity state:

  • Contracts: optional ProjectColor field on OrchestrationProject(Shell), project.meta.update, and ProjectMetaUpdatedPayload — optional/nullable everywhere so old servers and clients interop. New projectColor capability flag so clients hide the picker instead of sending commands a pre-color server would reject.
  • Server: migration 039_ProjectionProjectsColor adds a color column to projection_projects; decider, in-memory projector, projection pipeline, and snapshot queries thread the field through.
  • Web: projectColors.ts (palette + group-color resolution) and ProjectColor.tsx (ProjectColorDot, ProjectColorPicker). Colors are persisted as palette names and rendered via Tailwind color tokens, so dots stay legible in both light and dark themes. Dots are aria-hidden (the project name is always present as text); picker swatches carry labels and aria-pressed state.
  • Grouped projects (same repo across environments) resolve to one color, and setting it in any environment colors the group.

Testing

  • New decider/projector tests (set / clear / leave-unchanged) and a persistence round-trip test.
  • Full monorepo typecheck and lint clean; web (1942), client-runtime (588), contracts (226), and server (1912) suites pass. The only server-suite failures are 6 pre-existing environment-dependent ones (service-launcher version mismatch on the dev box), identical on a clean tree.

Not included (possible follow-ups)

  • Mobile parity (mobile ProjectFavicon sites don't render dots yet).
  • Dots in the command palette / draft-hero project pickers.

🤖 Generated with Claude Code


Note

Medium Risk
Touches orchestration commands, a DB migration on projection_projects, and multi-environment fan-out in project settings; mitigated by optional wire fields and capability gating for version skew.

Overview
Adds optional project colors end to end so repos can be distinguished by a small colored dot in the sidebar, chat header, and project settings.

Contracts & server: Introduces ProjectColor and nullable color on project snapshots and project.meta.update / project.meta-updated (omitted when unchanged). Migration 044_ProjectionProjectsColor adds color to projection_projects; the decider, projector, SQL projections, and snapshot queries persist and expose it. Servers advertise a projectColor capability so older peers are not sent unknown fields.

Web: Palette helpers (projectColors.ts) plus ProjectColorDot / ProjectColorPicker. Settings fans color out to capability-aware group members; grouped logical projects share one resolved color across environments. Dots are decorative (aria-hidden); the picker is labeled for accessibility.

Tests & docs: Decider/projector and DB round-trip coverage, plus user docs for setting colors.

Reviewed by Cursor Bugbot for commit faf3e3f. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add end-to-end project color support as an accessibility aid

  • Introduces a nullable color field across OrchestrationProject, OrchestrationProjectShell, ProjectMetaUpdateCommand, and ProjectMetaUpdatedPayload in orchestration.ts, plus an optional projectColor capability flag in environment.ts
  • Adds migration 44 to add a color TEXT column to projection_projects in 044_ProjectionProjectsColor.ts; the projection pipeline, projector, and snapshot queries now persist and return color
  • The server advertises projectColor: true in ServerEnvironment.ts; the project settings UI in ProjectSettingsPanel.tsx only renders the new ProjectColorPicker when at least one group member is color-capable, and fans out color updates only to capable members
  • Sidebar, thread rows, tooltips, search results, draft rows, chat header, and legacy sidebar now display a ProjectColorDot using group-level color resolution via new utilities in projectColors.ts
  • Behavioral Change: project.meta-updated events now conditionally carry color (absent = unchanged, null = cleared); getSnapshot, getShellSnapshot, and getActiveProjectById responses now include color, which older clients may ignore under version skew. The capability flag gates the UI; servers not advertising projectColor will not show the picker.

Macroscope summarized faf3e3f.

@coderabbitai

coderabbitaiBot commented Aug 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 70ad8f0b-414a-4acb-9bca-9b5a87efd236

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 30, 2026
Comment threadapps/web/src/components/ChatView.tsx Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/projectColors.ts

@macroscopeappmacroscopeappBot 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.

One finding on the new web palette module. Everything else — capability gating and RPC both resolved from member.environmentId, activeProject scoped to the thread's environment, ProjectColorDot placements inside MenuRadioItem's children wrapper, and the raw swatch buttons (exempt as swatches) — looks consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/projectColors.ts Outdated
Comment threadapps/web/src/components/SidebarV2.tsx Outdated
Comment threadapps/web/src/components/ChatView.tsx Outdated
@macroscopeapp

macroscopeappBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a persisted, cross-environment project-color capability with a new settings workflow and rendering across several production surfaces. Although it is opt-in and backward-compatible for uncolored projects, its cross-stack scope and multi-environment write behavior warrant human review.

You can add or adjust custom eligibility rules. Learn more.

Adds a per-project color, chosen from a theme-aware nine-swatch palette
in the sidebar's project actions dialog, shown as a small dot wherever
the project identifies itself: sidebar thread cards and compact rows,
search results, tooltips, the project filter menu, the Sidebar V1 group
header, and the chat header.
The color is stored server-side on project metadata (migration 039,
optional `color` on the project.meta.update command / meta-updated
event / project shells) so it syncs across devices, mirroring the
pinned-thread ordering precedent. A new `projectColor` capability flag
hides the picker for servers that predate it. Grouped projects share
one color across environments.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD
IAmJSDforce-pushed the t3code/add-repo-color-coding branch from 898f7f3 to 120e81cCompareAugust 30, 2026 16:54

@macroscopeappmacroscopeappBot 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.

Reviewed the web UI changes for shared-component, Tailwind ownership, and capability/environment-routing consistency. Two findings in apps/web/src/components/settings/ProjectSettingsPanel.tsx; the swatch/dot components themselves look consistent with the existing patterns.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx
- Group color now prefers the group representative's color over member
order, so a remote member can't override a colored primary checkout
(Macroscope, projectColors.ts).
- The chat header resolves the color through the same project grouping
as the sidebar, so a color set on another member of the logical
project still marks the thread (Macroscope + Cursor, ChatView).
- getCommandReadModel now maps projection_projects.color like the other
read-model builders (Macroscope, ProjectionSnapshotQuery).
- Palette CSS variables are literal var() strings owned by
projectColors.ts instead of runtime-built names, so Tailwind v4's
source scanner always emits them (Macroscope UI-consistency).
- Added unit tests for the color precedence and CSS value mapping.
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR from Astrid Gealer's session.

Addressed the bot review feedback in f28c54d (after rebasing onto main in 120e81c, which also moved the color picker from the old SidebarV2 dialog into the new ProjectSettingsPanel and renumbered the migration to 044):

  • Group color precedence (Macroscope): resolveProjectGroupColor now takes the group and prefers the representative's color before falling back to the first colored member, so a remote member can no longer override a colored primary checkout. Covered by new unit tests in projectColors.test.ts.
  • Chat header ignores group color (Macroscope + Cursor): ChatView now resolves the header color through the same buildProjectGroups grouping the sidebar uses (resolveProjectColorInGroups), instead of reading only the physical project's own color.
  • getCommandReadModel omits color (Macroscope): now maps color: row.color like the other read-model builders.
  • Tailwind v4 variable emission (Macroscope UI-consistency): palette values are now a static PROJECT_COLOR_VALUES record of literal var(--color-*-500) strings owned by projectColors.ts, used by both the dots and the picker — no more runtime-built variable names depending on the unrelated color-selector.tsx for emission.
  • Stale-snapshot guard blocking color changes (Macroscope + Cursor): this code no longer exists after the rebase — the picker moved to the project settings page, where the no-op guard compares against the live group state rather than a dialog-open snapshot.

🤖 Generated with Claude Code

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f28c54d. Configure here.

Comment threadapps/web/src/components/settings/ProjectSettingsPanel.tsx Outdated
…bing
- The project settings Color row now renders only when a member's server
advertises the projectColor capability, and the fan-out skips members
on pre-color servers — matching the contract comment and user docs
(Macroscope + Cursor).
- setProjectColor gets the same in-flight guard as setFaviconPath, and
the picker's disabled state is finally wired, so overlapping fan-outs
can't leave a group with mixed colors (Macroscope).
- getActiveProjectByWorkspaceRoot now copies row.color into the
OrchestrationProject it builds (Macroscope + Cursor).
Written by Claude Code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@IAmJSD

Copy link
Copy Markdown
Author

Note

This comment was written by Claude Code (Claude Fable 5), babysitting this PR.

Second round of bot feedback addressed in faf3e3f:

  • Capability gate (Macroscope UI-consistency + Cursor): the project settings Color row now renders only when at least one group member's server advertises the projectColor capability, and setProjectColor fans out only to capable members — pre-color servers are never sent the field, matching the contract comment and docs/user/project-colors.md.
  • In-flight guard (Macroscope): setProjectColor mirrors the adjacent setFaviconPath pattern (savingColorRef + isSavingColor), and the picker's previously-dead disabled prop is now wired, so two quick swatch clicks can't interleave fan-outs and leave the group with mixed colors.
  • getActiveProjectByWorkspaceRoot (Macroscope + Cursor): the hand-built OrchestrationProject now copies row.color, consistent with getSnapshot, getCommandReadModel, and mapProjectShellRow.

Validation: monorepo typecheck and lint clean; web suite 3013 passed; server projection/decider suites pass. The only failing server tests locally (bin.test.ts headless-connect and two ServerEnvironment.test.ts cases) reproduce identically on a clean upstream/main checkout on this machine — pre-existing environment issues, not from this PR.

🤖 Generated with Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@IAmJSD