Skip to content

feat: support URL icons in tool-icons.json#560

Open
kennyheard wants to merge 5 commits intolukilabs:mainfrom
kennyheard:feat/tool-icon-urls
Open

feat: support URL icons in tool-icons.json#560
kennyheard wants to merge 5 commits intolukilabs:mainfrom
kennyheard:feat/tool-icon-urls

Conversation

@kennyheard
Copy link
Copy Markdown

@kennyheard kennyheard commented Apr 17, 2026

Summary

Tool icons in tool-icons.json currently only support local filenames (e.g. "icon": "git.ico"). This adds support for URL values (e.g. "icon": "https://cdn.simpleicons.org/git/000/fff"), bringing tool icons in line with how source and skill icons already handle remote assets.

When a tool's icon is a URL, it is downloaded and cached as a local file in the tool-icons/ directory, keyed by tool ID (e.g. git.svg). This means icons are fetched once and served locally from that point on — no repeated network requests during rendering.

The download happens both at startup (via ensureToolIcons) and live while the app is running (via a new ConfigWatcher handler for tool-icons.json). When a tool is removed from the config, its cached icon file is cleaned up automatically.

As part of this change, the startup seeding logic was tightened so that only bundled icon files actually referenced by the config are copied — previously all bundled files were copied unconditionally.

Changes

  • cli-icon-resolver.ts: Added findToolIconFile to locate cached icon files by tool ID. Updated resolveToolIcon to check for cached local copies when the icon is a URL.
  • workspace.ts: Same resolution logic applied to the Settings > Appearance > Tool Icons handler so the UI correctly displays URL-based icons.
  • storage.ts: Reworked ensureToolIcons to download URL icons on first run, seed only referenced bundled icons, and clean up orphaned files.
  • watcher.ts: Added a file watcher for tool-icons.json that downloads new URL icons and removes orphaned files when the config changes at runtime.

Test plan

Note: tool-icons.json is typically edited by the agent on the user's behalf, not manually.

  • Ask the agent to set a tool icon to a URL
  • Verify the icon renders in Settings > Appearance > Tool Icons
  • Verify the icon renders on CLI tool turn cards in chat
  • Confirm the icon file has been downloaded to ~/.craft-agent/tool-icons/
  • Ask the agent to remove a tool — verify its cached icon file is cleaned up
  • Verify icon changes take effect immediately without restarting the app
  • Verify existing local filename icons continue to work

URL icons are downloaded and cached locally on startup and when the
config changes, matching how source and skill icons work. Orphaned
icon files are cleaned up when tools are removed from the config.
…cons

When a tool's icon is a URL, check for the specific file downloadIcon
would produce ({toolId}.{ext} derived from URL, defaulting to .svg)
rather than using findToolIconFile which matches any extension. This
prevents stale bundled files (e.g. git.ico) from blocking the download
of the correct CDN version (git.svg).
@kennyheard kennyheard force-pushed the feat/tool-icon-urls branch from e278484 to 398c017 Compare April 21, 2026 07:36
loadIconFile and discoverIconFile now return ResolvedEntityIcon directly,
eliminating the intermediate { dataUrl, colorable, rawSvg } shape and the
manual reconstruction in useEntityIcon.
Tool icons in settings now render through EntityIcon (same as source/skill
icons) instead of <img> tags. The server sends raw SVG content alongside
the data URL, and the renderer resolves it via resolveRawSvgIcon.
…ering

resolveRawSvgIcon now strips embedded <style> blocks and replaces all
hardcoded fill colors with currentColor before rendering inline. This
makes SVG icons (from CDNs like Simple Icons) inherit the text color
instead of displaying their brand color.

Icons with fill="none" (multi-color SVGs) are left untouched.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant