feat(skills): publish skills to the team and install team skills locally#2610
Merged
Conversation
This was referenced Jun 11, 2026
Contributor
Author
This was referenced Jun 11, 2026
|
React Doctor could not complete this scan.
Reviewed by React Doctor for commit |
Contributor
Prompt To Fix All With AIFix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
packages/workspace-server/src/services/skills/skills.ts:248-263
**Partial write left on disk when file-path validation fails**
`resolveSkillFilePath` is called inside the write loop — after `mkdir(target)` and `writeFile(SKILL.md)` have already run. If any companion file carries a path that escapes the skill directory, the validation throws and the partially-created `~/.claude/skills/<name>` directory (with `SKILL.md` already written) is left on disk. The next call to `installTeamSkill` with the same name (and no `overwrite: true`) then fails with "already exists" instead of the real validation error — the test's `finally { rm(target) }` block papers over this exact scenario.
Validate all resolved paths before touching the filesystem: compute each `filePath` against `target` first, collect them, then proceed with `mkdir`/`writeFile`.
### Issue 2 of 3
packages/ui/src/features/skills/TeamSkillDetailPanel.tsx:51
The "already exists" detection relies on substring-matching the error message. If the server-side error text ever changes (e.g., a future i18n change or message reword), the overwrite dialog will silently stop appearing and the user will see a generic "Failed to install skill" toast instead.
```suggestion
if (!overwrite && (message.includes("already exists") || message.includes("already installed"))) {
```
### Issue 3 of 3
packages/core/src/skills/teamSkillsService.ts:24-29
**Duplicate `ExportedSkill` type (OnceAndOnlyOnce)**
`ExportedSkill` is now defined in both `packages/core/src/skills/teamSkillsService.ts` (files-only shape) and `packages/workspace-server/src/services/skills/schemas.ts` (same shape + `skipped`). The two definitions are structurally compatible today, but they can drift independently. The workspace-server type is the canonical one since it's the Zod schema that validates the tRPC wire format — the core type could simply re-export or `Omit<ExportedSkill, 'skipped'>` from it.
Reviews (1): Last reviewed commit: "feat(skills): publish skills to the team..." | Re-trigger Greptile |
jonathanlab
approved these changes
Jun 11, 2026
k11kirky
added a commit
that referenced
this pull request
Jun 12, 2026
…rt tests hermetic Review feedback on #2610/#2611: the "already exists" overwrite detection now keys off SKILL_EXISTS_MARKER in @posthog/shared, used verbatim by the server messages and the UI matcher, so a reword cannot silently break the overwrite dialog; getUserSkillsDir is mocked in skills.test.ts so the codex-import and team-install tests run fully against temp dirs instead of early-returning when the real home directory has a colliding skill. Generated-By: PostHog Code Task-Id: f4e84f1a-19c9-490c-9b98-47787a7dddcf
829fa8e to
ee58852
Compare
a72917a to
975d78b
Compare
k11kirky
added a commit
that referenced
this pull request
Jun 12, 2026
…rt tests hermetic Review feedback on #2610/#2611: the "already exists" overwrite detection now keys off SKILL_EXISTS_MARKER in @posthog/shared, used verbatim by the server messages and the UI matcher, so a reword cannot silently break the overwrite dialog; getUserSkillsDir is mocked in skills.test.ts so the codex-import and team-install tests run fully against temp dirs instead of early-returning when the real home directory has a colliding skill. Generated-By: PostHog Code Task-Id: f4e84f1a-19c9-490c-9b98-47787a7dddcf
975d78b to
eb09670
Compare
ee58852 to
a397721
Compare
Contributor
Author
Merge activity
|
k11kirky
added a commit
that referenced
this pull request
Jun 12, 2026
…rt tests hermetic Review feedback on #2610/#2611: the "already exists" overwrite detection now keys off SKILL_EXISTS_MARKER in @posthog/shared, used verbatim by the server messages and the UI matcher, so a reword cannot silently break the overwrite dialog; getUserSkillsDir is mocked in skills.test.ts so the codex-import and team-install tests run fully against temp dirs instead of early-returning when the real home directory has a colliding skill. Generated-By: PostHog Code Task-Id: f4e84f1a-19c9-490c-9b98-47787a7dddcf
a397721 to
db84e11
Compare
eb09670 to
a188d67
Compare
Publish: - SkillsService.exportSkill reads a writable skill directory into a publishable shape: frontmatter split out (name/description), body without frontmatter, and every text companion file; binary or oversized files are skipped and reported. - TeamSkillsService.publishSkill (core) decides create-vs-new-version: first publish creates the LLMSkill, re-publishing PATCHes name-addressed with base_version so versioning comes free from the model's version/is_latest (409 surfaces as a clear error). Publishing requires a description. - api-client createLlmSkill / publishLlmSkillVersion. - "Publish to team" action on editable skills with confirmation; the success toast reports any skipped files. Install locally: - TeamSkillsService.fetchSkillForInstall pulls the body plus every companion file; skills.installTeamSkill (workspace-server) materializes it into ~/.claude/skills with the existing frontmatter writer, name validation, and path-safety guards. Copy-and-forget: reinstall-to-update via the Team group with a confirm-overwrite. - Install/Reinstall button on the team skill panel. Generated-By: PostHog Code Task-Id: f4e84f1a-19c9-490c-9b98-47787a7dddcf
…-owned orchestration Review feedback on #2610: - installTeamSkill stages all writes (and path validation) in a hidden temp dir and swaps it into place, restoring the previous copy if the swap fails — no partial directories, no destroyed local skills - ExportedSkill now lives in @posthog/shared; the workspace-server wire schemas are pinned to it with `satisfies`, removing the drift-prone duplicate definition - publish/install orchestration moved from the UI hooks into TeamSkillsService (workspace access via an injected client slice per the repo's hook rule); hooks now wrap exactly one service call - skill discovery ignores hidden directories Generated-By: PostHog Code Task-Id: f4e84f1a-19c9-490c-9b98-47787a7dddcf
a188d67 to
12ec1c5
Compare
k11kirky
added a commit
that referenced
this pull request
Jun 12, 2026
…rt tests hermetic Review feedback on #2610/#2611: the "already exists" overwrite detection now keys off SKILL_EXISTS_MARKER in @posthog/shared, used verbatim by the server messages and the UI matcher, so a reword cannot silently break the overwrite dialog; getUserSkillsDir is mocked in skills.test.ts so the codex-import and team-install tests run fully against temp dirs instead of early-returning when the real home directory has a colliding skill. Generated-By: PostHog Code Task-Id: f4e84f1a-19c9-490c-9b98-47787a7dddcf
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.

Problem
Team skills exist as a read-only concept — users can browse them but have no way to publish a local skill to the team or install a team skill onto their machine. This blocks the core share-and-reuse workflow for team skills.
Changes
Publishing local skills to the team
createLlmSkillandpublishLlmSkillVersionAPI client methods, along with theLlmSkillFileInputinterface, to support creating a new skill and bumping its version respectively.publishSkilltoTeamSkillsService, which creates the skill on first publish or patches a new version against the current latest. Validates that a name and description are present before calling the API.exportSkilltoSkillsService, which reads a writable skill directory into a publishable shape: frontmatter is split out, the body is extracted, and every text companion file is included. Binary files and files exceeding the size limit are skipped and reported back to the caller.exporttRPC procedure and ausePublishSkillmutation hook. A "Publish to team" button (cloud-upload icon) appears inSkillDetailPanelwhencanPublishis true, guarded by a confirmation dialog. On success, a toast shows the published version number and any skipped files.Installing team skills locally
fetchSkillForInstalltoTeamSkillsService, which fetches the latest skill body and resolves every companion file's content in parallel.installTeamSkilltoSkillsService, which materializes the skill under~/.claude/skills. Validates the skill name, guards against path traversal in companion file paths, and requires an explicitoverwrite: trueflag if the skill already exists locally.installTeamSkilltRPC procedure and auseInstallTeamSkillmutation hook. An Install/Reinstall button appears inTeamSkillDetailPanel. If the skill already exists, an overwrite confirmation dialog is shown before proceeding.How did you test this?
TeamSkillsService.publishSkillcovering first-publish (create), subsequent publish (version bump), missing description, and unavailable feature.TeamSkillsService.fetchSkillForInstallverifying that the body and all companion file contents are resolved.exportSkillverifying frontmatter extraction, companion file collection, binary file skipping, and access denial for non-writable skills.installTeamSkillcovering the happy path, the overwrite guard, invalid skill names, and path traversal rejection.Automatic notifications