Skip to content

fix: save custom project icon for local projects (two bugs) #34301

Closed as duplicate

Description

@ngleoi

Bug: Edit Project dialog fails to save/clear custom icon for local projects

Description

When editing a project in the OpenCode Desktop app (v1.17.11), the "Edit Project" dialog has two separate bugs that affect local projects:

  1. Icon save silently ignored — setting a new custom icon has no effect on local projects
  2. Icon clear reverts to stale override — clearing a custom icon shows the old override instead of the default colored-first-letter avatar

Bug 1: Missing project.icon() call in local project branch

Steps to Reproduce:

  1. Open a local project
  2. Right-click → "Edit Project"
  3. Change the icon (drag an image or click to select)
  4. Click "Save"
  5. The dialog closes, but the project icon remains unchanged
  6. Reopen "Edit Project" — the icon field has reverted

Root Cause:
In dialog-edit-project-Cy5SF5th.js, the saveMutation has two code paths:

Remote project path (works):

serverSync().project.icon(props.project.worktree, store.iconOverride || void 0);  // saves icon
serverSync().project.meta(props.project.worktree, { ... });
dialog.close();
return;

Local project path (bug):

// Missing: serverSync().project.icon() call
serverSync().project.meta(props.project.worktree, { ... });  // only saves meta, NOT icon
dialog.close();

The project.icon() call is entirely missing from the local branch, so any icon override is silently discarded.

Bug 2: Enrich function reads stale metadata from global store after clearing icon

Steps to Reproduce:

  1. Open a local project that previously had a custom icon set
  2. Right-click → "Edit Project"
  3. Click the "Clear" icon button
  4. Click "Save"
  5. The project list still shows the old override icon instead of the default colored-first-letter avatar

Root Cause:
The enrich() function in main-D_cwiNV1.js:74725 builds the project display object from two sources:

  • metadata: from sync2.data.project (a global SolidJS store populated from the server API)
  • project2: the raw project object from server.projects.list()

When childStore.icon is falsy (after clearing), enrich() falls through to return { ...metadata, ...project2 }. The metadata still contains the stale icon.override because:

  • project.icon() updates only childStore.icon (local child store)
  • project.meta() updates only childStore.projectMeta (local child store)
  • Neither updates sync2.data.project (the global store that enrich() reads)

For remote projects, serverSDK().client.project.update() triggers a "project.updated" SSE event that flows through applyGlobalEvent → setGlobalProject, which updates sync2.data.project. For local projects, no such event is fired, so the stale override persists in the cache.

Combined Fix

Both bugs are in dialog-edit-project-Cy5SF5th.js. The local project branch needs:

  1. Add the missing project.icon() call before project.meta()
  2. After project.meta(), also update sync2.data.project directly via serverSync().set()

Full corrected local branch:

serverSync().project.icon(props.project.worktree, store.iconOverride || void 0);
serverSync().project.meta(props.project.worktree, {
  name,
  icon: {
    color: store.color || void 0,
    override: store.iconOverride || void 0
  },
  commands: {
    start: start || void 0
  }
});
// Also sync the global store so enrich() picks up the change
serverSync().set("project", (prev) => {
  const wt = props.project.worktree;
  const idx = prev.findIndex(p => p.worktree === wt);
  if (idx === -1) return prev;
  const next = prev.slice();
  next[idx] = {
    ...next[idx],
    icon: {
      ...(next[idx].icon || {}),
      override: store.iconOverride || void 0,
      color: store.color || void 0
    },
    name,
    commands: { start: start || void 0 }
  };
  return next;
});
dialog.close();

Environment

  • Desktop App Version: v1.17.11
  • OS: Windows
  • Package: @opencode-ai/desktop (Electron)
  • Renderer file: dialog-edit-project-Cy5SF5th.js
  • Main file: main-D_cwiNV1.js

Activity

  1. github-actions commented on Jun 28, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    If your issue is specifically about the local-vs-remote code path distinction you identified, that root cause analysis may be a valuable addition to one of the existing issues.

  2. changed the title [-]fix: save custom project icon for local projects[/-] [+]fix: save custom project icon for local projects (two bugs)[/+] on Jun 29, 2026
  3. ngleoi commented on Jun 29, 2026

    @ngleoi
    Author

    UPDATE: Root cause fully identified

    There are two enrich() functions in main-D_cwiNV1.js, at lines 74725 and 75932. Both merge server project metadata with local persisted cache (childStore.projectMeta).

    • Line 74725 enrich(): Used for the projectsList memo – already included ...childStore.projectMeta.
    • Line 75932 enrich(): Used for enriched → list2 memos (which feed the auto-color assignment at line 76023 and the project avatar UI). This one was MISSING ...childStore.projectMeta.

    Startup race

    1. Server sends project list via SSE → sync2.data.project populated (with lobster icon.url)
    2. Second enrich() runs → base2 = { ...metadata, ...project2 } (NO local cache merge) → avatar shows lobster
    3. Auto-color code (line 76035) checks project2.icon?.url → lobster URL is truthy → skips color assignment
    4. Local persisted cache (childStore.projectMeta with url: void 0) loads async via onPersistedInit → first enrich() picks it up, but second enrich() ignores it entirely

    Fix applied (3 layers)

    Layer File Change
    1 dialog-edit-project-Cy5SF5th.js project.meta() patch includes url: void 0; sync.set() updater also clears url; serverSDK().client.project.update() called for local projects with url: ""
    2 main-D_cwiNV1.js (line 74725) First enrich() spreads ...childStore.projectMeta over server metadata
    3 main-D_cwiNV1.js (line 75932) NEW – Second enrich() now also spreads ...childStore.projectMeta

    Relevant files

    • out/renderer/assets/dialog-edit-project-Cy5SF5th.js — dialog save logic
    • out/renderer/assets/main-D_cwiNV1.js — two enrich() functions, projectMeta(), getProjectAvatarSource()
  4. codeface-io commented on Jul 5, 2026

    @codeface-io

    You've done so much work for a bug report 💪🏻
    What does it take to get something like this merged?
    Seems like a trivial bug that makes the app feel brittle.

  5. yiyinideshang commented on Jul 16, 2026

    @yiyinideshang

    You've done so much work for a bug report 💪🏻 What does it take to get something like this merged? Seems like a trivial bug that makes the app feel brittle.

    Oh no, buddy. This insignificant bug has been bothering me for quite some time. Do you have a colleague who is in charge of this task? Could you have him add this feature as an extra step when submitting the commit? Otherwise, don't say that it's useless.

  6. remotxavier commented on Sep 8, 2026

    @remotxavier

    @Hona @thdxr — any chance of getting this PR reviewed? It's been sitting since late June with a documented fix for two bugs affecting local projects (icon + name not saving in the Edit Project dialog). Confirming it still reproduces on OpenCode Desktop 1.18.14, macOS 26.5.2. Both symptoms make the Edit Project dialog effectively unusable for local projects (which are common for anyone opening OpenCode without a Git repo). Would be a big usability win to get this merged.

  7. neriousy commented on Oct 1, 2026

    @neriousy
    Member

    Closing as a duplicate of #32708, which tracks the Edit Project dialog not saving custom icons (and names) for local projects. Please follow and 👍 there.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions