Repository navigation
feat(app): discover project icons and names automatically - #56698
Open
kitlangton wants to merge 3 commits into
Open
kitlangton wants to merge 3 commits into
kitlangton wants to merge 3 commits into
Conversation
kitlangton
force-pushed
the
project-icons
branch
from
October 18, 2026 06:05
07ddc4f to
e37eea8
Compare
This branch has not been deployed
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.
Why
V1 found project icons automatically. That was lost when
packages/opencodewas removed for V2:project.icon_urlis still read, but nothing writes it, so every project in the desktop sidebar is a gray single-letter tile. Names are often wrong too. A project whose first clone lives in an oddly named folder keeps that folder's name: an oldvoice-controlclone makes Hex show "V", and a main worktree folder namedrewritemakes team-board show "R". The built-in OpenCode icon is also broken, because it compares against the V1 root-commit project ID.This builds on @Brendonovich's #45218, which added icon candidate discovery and a picker in project settings. It was never reviewed and was closed as stale. His commit is kept here with his authorship, ported to the current
beta.What Changes
Automatic icon. The server finds a project's icon in the background, stores it with the project, and lists it in
/api/project. Discovery takes the first match in this order:iconin the project'sopencode.json(c)or.opencode/opencode.json(c)(path orhttps:/data:URL){ "icon": "./brand/mark.png" }*.appiconset, the front layer of an Icon Composer*.icon(fromicon.json),app-icon.*build/icon.{svg,png},src-tauri/icons/*,resources/icon.*,icons/icon.*favicon*.{svg,png,ico},apple-touch-icon*.png, Nextapp/icon.*logo.*/icon.*at the root or inassets/,public/,static/,images/,docs/,.github/…Within a rank, an SVG wins, then a larger square raster, then the shallower path. Discovery is bounded:
.github) plus dependency, build-output and fixture trees such asnode_modules,dist,target,Pods,test,fixturesandartifacts.build/is never listed, butbuild/icon.*is checked.On my real repos, discovery took 1–35 ms.
Your choice always wins. On the client, an uploaded or picked override comes first, then a chosen color tile, then the discovered icon. Discovery writes only its own column and never touches the override or the color.
Picker. Project settings shows a "Detected icons" row (from #45218). It has an "Automatic" choice first, followed by up to 12 ranked candidates. Picking a candidate saves it as the override. Picking Automatic clears the override and the color.
Name from the git remote. Projects get a
repositoryfield taken from theoriginremote. Clients displayname, thenrepository, then the folder name:git@github.com:acme/team-board.gitteam-boardhttps://github.com/acme/hexhexssh://git@gitlab.com/group/sub/tool.git/toolfile:///tmp/repo.gitor no remoteFallback tile. A project with no icon and no chosen color gets a stable color derived from its ID instead of gray. It uses the existing avatar color variants, excluding gray. With no color chosen, the color picker no longer shows gray as selected.
OpenCode icon. The OpenCode project is now matched by the V2 IDs for
github.com/anomalyco/opencodeandgithub.com/sst/opencode. The V1 ID is kept. A user's override now beats the built-in OpenCode icon.Icon Delivery
/api/projectonly adds fields; the existing response shape is unchanged:{ "id": "…", "canonical": "/src/team-board/rewrite", "repository": "team-board", // new "icon": { "override": "data:…", // unchanged (user upload / picked candidate) "color": "blue", // unchanged "discovered": { // new "url": "/api/project/<id>/icon?v=<content-hash>", "path": "public/favicon.svg" } } }GET /api/project/:projectID/iconserves the discovered file's bytes with its content type andETag: "<hash>".?v=getsCache-Control: private, max-age=31536000, immutable. Any other request getsprivate, no-cache.If-None-Matchreturns 304.iconin the project config is an absolute URL,discovered.urlis that URL.Refresh. Discovery runs:
It never blocks a request. Changes go out through the existing ephemeral
project.updatedevent, and no new durable events are added. A migration adds two nullable columns:project.repositoryandproject.icon_discovered.Demo
Headless Chromium through the app's Playwright mock harness. The fixture projects are fictional: an Xcode app (
orbit), an Electron app (lantern), a web app whose clone sits inold-clone(meadow), a plain repo with no icon (quill), and a repo whose main worktree folder isrewrite(tidepool).Before (
beta):After:
Project settings picker:
Scope
This PR covers server discovery, the wire fields, the icon route, and the desktop. iOS will read
repositoryandicon.discoveredseparately. Two things are left for follow-ups: compositing Icon Composer layers over theirfill, and reading inline<link rel="icon">fromindex.html. Agit@host:pathremote without a user (host:path) still has no repository name, because the project-ID parser rejects it and changing that would change existing project IDs.Verification
appiconset, Icon Composer front layer, Tauri sizes, Electronbuild/icon.png, Nextapp/icon.png,public/favicon.svgvs.ico, logos), the config override (path, URL, path outside the project), the 1 MB cap, the depth limit, skipped dependency and fixture trees, remote-name parsing, and user choices surviving discovery and reset.lint:changedreports 5 warnings, all on lines that already existed (typeofchecks and an unannotated assertion in touched files). None are from this change.