Repository navigation
Give every repository one colour, and show it everywhere - #167
Merged
Merged
Conversation
A workspace holds several repositories at once and only the roadmap band said which was which. The filter above the backlog, the entries in it and the agent sessions under them all read the same in every project, so telling one project's work from another's meant reading the alias on every row. The design system already sanctioned five identity hues — it just fenced them to the roadmap band. Widen the fence rather than invent colour, and make the mark additive: a 4px rule down the leading edge, painted as an inset shadow so no element's box, padding or alignment moves. Every surface, border and text token stays exactly as it was, which is the whole reason the set may leave the roadmap. A band is a region of a chart and can afford a 24% wash; a filter chip and an entry row sit in dense chrome that already spends its contrast on status, priority and selection, and a wash there would put identity in competition with colour that carries meaning. The choice moves out of the roadmap plan file and into the repository it is about. It was stored per plan, which made it a fact about one chart — but four surfaces now read it, and a surface that worked its own out would be a second answer to which colour a project is. So GitHubRepositoryRef carries the number, one resolver in RepositoryColours answers for everyone, and the roadmap is told its hues rather than choosing them. Its in-band picker and the whole ColourBand feature go with it: one choice, one place. The active scope chip is the one case a contrast ratio cannot answer. It is filled with color-primary, and color-band-1 *is* color-primary, so a band-1 rule there would measure 1:1 and disappear. It is held off the fill by a 1px seam in color-background, which clears 3:1 on both sides. Colour is never the sole carrier: every marked surface still writes the alias and every mark is aria-hidden. A session group with no heading gets no hue at all, because the heading is where its repository is named. One deliberate behaviour change. The roadmap used to number hues over the bands it happened to draw, so a repository with nothing planned let its neighbour slide to a lower hue. It now keeps the hue Settings gave it — otherwise the same project would be one colour on the filter and another on the chart, which is the thing this change exists to fix. Band colours in an existing plan file are carried onto the repository the first time the roadmap opens, and never over a choice made in Settings since. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The code change moved the choice out of the roadmap plan and onto the repository, and two governed chapters still described the old arrangement. The roadmap sub-feature said the choice "is kept with the plan", which is now the opposite of what happens and would send the next reader looking for it in the wrong context. Repository Management gains the sub-feature, because that is where the fact belongs: one colour per registered repository, recorded as which of the sanctioned ones rather than as a colour, placed automatically by position when nobody has chosen, and returnable to that placement. The roadmap chapter keeps its sub-feature — reading a portfolio plan one project at a time is still a roadmap concern — but now says the plan is *told* the colour and stores nothing, for the same reason it holds repository aliases as opaque strings. It also records what the unfiled and dates bands do, which the prose had left out: they take no colour, because a colour there means "which repository" and neither of them is one. The derived _meta graphs are regenerated with them. They were already stale for the .design chapter edited in the previous commit — build.mjs --check validates index ordering rather than graph content, so it passed without noticing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Only the three derived _meta graphs conflicted, and a hand-merged generated file is a file that disagrees with its generator. Took either side and ran build.mjs, which is the only thing entitled to write them. Main's storage refactor took RepositoryBacklogSource away, and this branch's new HomeRepositoryScopeTests carried a copy of the Home harness written against it. The harness is copied from HomeWorkspaceSurfaceTests again so it tracks whatever that one composes now, with only the two-repository setup this test needs on top. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Main brought a Sessions area with a Repository column, which is the surface this change was asked to cover and could not: when the work started, sessions existed only in the shared library and the storybook. Now they are on screen, so they get the same mark as everything else. Beside the repository name rather than down the row. A row here is a session and the repository is one of eight things it reports; a rule down its leading edge would read as if the session itself belonged to that project, which is not what the row is about. On the cell, the name is right there — which is also where the design rule wants the mark, since it is never the sole carrier. The pane is told the colour rather than looking it up, the same way the roadmap and the entry list are. This context holds owner/name as an opaque string on purpose, and resolving it here would tie sessions to repository management for a decoration. The shell answers, so all five surfaces read one answer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 20, 2026
This was referenced Oct 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A workspace holds several repositories at once, and only the roadmap band said which was which. The filter above the backlog, the entries in it and the agent sessions under them read identically in every project, so telling one project's work from another's meant reading the alias on every row.
This gives each configured repository one colour, chosen once in Settings → Repositories, and shows it as a small marker on every surface where that repository appears.
The design system already sanctioned five identity hues (
--color-band-1..5) — it just fenced them to the roadmap band. This widens the fence rather than inventing colour: the palette is unchanged, and the count of distinct colours the product declares stays at twenty-five.Nothing in the existing design is given up. The mark is a 4px rule down the leading edge, painted as an inset shadow rather than a border, so no element's box, padding or alignment moves. Chips take the extra 4px out of their own leading padding, so a coloured chip is exactly as wide as an uncoloured one beside it. Every surface, border and text token each control already wore is untouched — the hue is added to what was correct, never replacing part of it.
That restraint is why the set may leave the roadmap at all. A band is a region of a chart and can afford a 24% wash; a filter chip and an entry row sit in dense chrome that already spends its contrast on status, priority and selection. A wash there would put an identity hue in competition with colour that carries meaning, which is the one thing the design rule forbids.
Changes
Design rule — a precondition, not a follow-up.
.design/color-scheme.md#band-identity-tokenssaid "Nothing outside a roadmap band may use one" and required a new consumer to justify itself against that section. It is now a named consumer table (filter chip, roadmap, entry row, session group, and the Settings picker) with the identity-edge painting rule and thecolor-background-raisedcontrast measurements added. Binding pair iscolor-band-5at 4.01:1 as an edge on a raised surface, a third above the 3:1 a non-text mark owes.Storage and resolution.
GitHubRepositoryRef.Colour(int?, 1–5) besideCloneDirectory/Token/KnowledgeFolders, persisted in the per-usergithub.jsonand preserved when the repository list is retyped.GitHubSettingsStore.SetRepositoryColourfollows the house no-save-button rule. One resolver,RepositoryColours.Resolve: an explicit choice wins, everything else takes its position stepping over the hues already claimed, wrapping after five.Rendering. A shared
.repo-mark/.repo-mark--Nutility. Applied to the header scope chip, entry rows, the integration link list's repository group, and the repository cell of a row in the Sessions area. Entry rows get it through a newTaskListView.RowCssClasshook rather than a field onTaskRow— that record is deliberately a task and not an entry, and a list of checklist steps has no repository to answer with.Settings. A swatch radiogroup plus Reset to default in the per-repository tab, with a status line stating the effective colour in words.
Roadmap.
PlannedRepositorygainsColourand is told its hues instead of choosing them;RoadmapPlanViewno longer readsplan.Bandsor runs its own allocator. The in-band Colours picker and the wholeColourBandfeature — command, handler,IRoadmapPlanning.ColourBandAsync,RoadmapPlan.ColourBand, its error — are removed. One choice, one place.Migration.
RoadmapBand.CarryOverPlanColoursseeds Settings from an existing plan file'sbandsmap, only for repositories with no colour of their own, so a choice made in Settings since is never overwritten.Two things a reviewer should know
The active scope chip is the one case a contrast ratio cannot answer. It is filled with
color-primary, andcolor-band-1iscolor-primary— a band-1 rule there measures 1:1 and disappears. It is held off the fill by a 1px seam incolor-background, which clears 3:1 on both sides (11.15:1 each way). Verified live: computedbox-shadowreadsrgb(242,193,78) 4px inset, rgb(18,18,20) 5px insetwith the same colour behind it.One deliberate behaviour change. The roadmap used to number hues over the bands it happened to draw, so a repository with nothing planned let its neighbour slide to a lower hue. It now keeps the hue Settings gave it whether or not its neighbours have work — otherwise the same project would be one colour on the filter and another on the chart, which is the thing this change exists to fix.
HuesAreCountedOverTheBandsDrawn_NotOverEveryConfiguredRepositoryasserted the old behaviour and was rewritten rather than patched.Accessibility
Colour is identity and never meaning — it sits beside status, priority and selection rather than behind them. It is never the sole carrier: every marked surface still writes the repository alias and every mark is
aria-hidden. A session group with no heading gets no hue at all, because the heading is where its repository is named.Testing
dotnet build Backlog.sln— 0 errors, 0 warnings.dotnet test Backlog.sln— 2,356 passed, 0 failed across 11 projects (after mergingmain). 29 new tests:RepositoryColourTests(14)SettingsRepositoryColourTests(5)HomeRepositoryScopeTests(4)BacklogPaneRepositoryColourTests(4)IntegrationLinkListTests(+3)SessionsPaneTests(+3)RoadmapBandDatesAndColoursTestsnode .github/tools/knowledge-meta/build.mjs --check— clean.Manual QA with Playwright against
desktop-web-harnessandui-storybookunder Aspire — 8 scenarios, all pass, no console errors and no Aspire errors:github.jsonon each click, and Reset cleared it while leaving the repository with its positional hue._roadmap/plan.jsonwithbands: {backlog: 3}from an earlier session, and the app carried it onto the repository on first render.Running Aspire for this checkout was stopped with
build\stop-aspire-before-pr.ps1, scoped to this worktree so parallel sessions were left alone.Related
.design/color-scheme.md#band-identity-tokens— amended by this PR; it forbade the change until it was..domain/roadmap/features.md#feature-repository-scoped-planning— the roadmap feature the hue set was originally introduced for.After merging
mainmainbrought a Sessions area with a Repository column, added while this branch was in flight. That is the surface the request named and this branch could not reach at the time — sessions existed only in the shared library. It is now covered: the repository cell carries the mark, beside the name rather than down the row, because a row there is a session and the repository is one of eight things it reports.The pane is told the colour rather than looking it up, the same way the roadmap and the entry list are — the Sessions context holds
owner/nameas an opaque string on purpose, and resolving it there would tie sessions to repository management for a decoration.Merging also resolved conflicts in three derived
_metagraphs. Generated files were regenerated rather than hand-merged, andHomeRepositoryScopeTestshad its copy of the Home harness refreshed fromHomeWorkspaceSurfaceTestsaftermain's storage refactor removedRepositoryBacklogSource.Follow-up
IntegrationLinkList— the per-entry panel that groups linked issues, PRs and agent sessions by repository — is still not wired into the desktop app. The mark is implemented on the component and demonstrated in the Storybook, so it arrives with the panel when that surface is adopted. This is separate from the Sessions area above.Checklist
build\stop-aspire-before-pr.ps1)🤖 Generated with Claude Code