Install is copy-and-forget: download, extract into
~/.claude/skills/<name>, done. From that moment it is an ordinary,
editable user skill — no upstream tracking, no hashes, no update
checks. Reinstall (confirm + overwrite) is the update story.
- SkillsMarketplaceService (workspace-server): search hits the
skills.sh index at runtime (nothing cached to disk); preview
downloads the repo zip from GitHub codeload, extracts in memory with
the existing fflate unzipAsync, and returns the full file list +
contents; install writes the skill directory and records
{version, installed: {name: {repo}}} in ~/.claude/skills/
installed.json, whose only purpose is the "Installed" badge.
- Safety: repo refs validated against owner/repo, skill ids against
the directory-name rules, zip entries screened for zip-slip, binary/
oversized files excluded from preview, 100 MB archive cap.
- skills.marketplace.* host-router routes (one-line forwards).
- UI: Browse tab in SkillsView with debounced search, install counts,
"Installed" badges, full file-tree preview before install (PR 1
components), an explicit warning chip when a skill contains
scripts/, and a confirm-overwrite reinstall flow.
- No new dependencies; fflate was already in workspace-server.
Note: the GitHub-search fallback mentioned in the plan is omitted —
unauthenticated GitHub code search cannot find SKILL.md directories;
search errors surface in the UI instead.
Generated-By: PostHog Code
Task-Id: f4e84f1a-19c9-490c-9b98-47787a7dddcf
Problem
Users have no way to discover and install community skills from within the app. They must manually find and copy skill files, with no browsing, previewing, or one-click install experience.
Changes
Backend:
SkillsMarketplaceServiceskills-marketplaceservice that integrates with theskills.shsearch API to find community skills by query.preview()returns all files in a skill directory before anything touches disk, flagging skills that contain executable scripts and marking binary files as non-previewable.install()extracts the skill into~/.claude/skills/<skillId>as an ordinary editable user skill. Aninstalled.jsonstate file tracks which skills came from the marketplace solely to power the "Installed" badge in search results.validateSkillDirNameis exported from the skills service so the marketplace service can reuse it.skills.marketplace.{search,preview,install}.Frontend: Marketplace UI
SkillsViewgains an "Installed" / "Marketplace" tab bar. The existing skills list is shown under "Installed"; the newMarketplaceBrowsecomponent is shown under "Marketplace".MarketplaceBrowseprovides a debounced search input (300 ms) that queries the marketplace. Results show skill name, source repo, install count, and an "Installed" badge when applicable. Selecting a result opens a resizableMarketplaceSkillPanelsidebar.MarketplaceSkillPanelshows a full pre-install file preview.SKILL.mdis rendered as Markdown (frontmatter stripped); all other files open in the read-only CodeMirror editor. A warning callout is shown when the skill contains scripts. Installing a skill that already exists locally prompts an overwrite confirmation dialog.stripFrontmatteris extracted into its own module and shared betweenSkillDetailPanelandMarketplaceSkillPanel.useMarketplaceSearch,useMarketplacePreview,useInstallMarketplaceSkill) are added inuseMarketplace.ts. A successful install invalidates the skills query so the "Installed" tab reflects the new skill immediately.How did you test this?
A full unit test suite was added for
SkillsMarketplaceServicecovering:findSkillDirPrefix— shallowest-match selection and absent-skill handling.collectSkillFiles— zip-slip path traversal rejection.search— correct mapping ofskills.shresults, installed-state decoration, and short-query early-exit.preview— full file list with contents, binary file detection, missing-skill error, and invalid repository reference rejection.install— successful extraction and state file write, overwrite guard and replacement, and invalid skill ID rejection.Automatic notifications