Skip to content

feat(skills): publish skills to the team and install team skills locally#2610

Merged
k11kirky merged 2 commits into
mainfrom
posthog-code/skills-06b-team-publish
Jun 12, 2026
Merged

feat(skills): publish skills to the team and install team skills locally#2610
k11kirky merged 2 commits into
mainfrom
posthog-code/skills-06b-team-publish

Conversation

@k11kirky

@k11kirky k11kirky commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

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

  • Added createLlmSkill and publishLlmSkillVersion API client methods, along with the LlmSkillFileInput interface, to support creating a new skill and bumping its version respectively.
  • Added publishSkill to TeamSkillsService, 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.
  • Added exportSkill to SkillsService, 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.
  • Wired up an export tRPC procedure and a usePublishSkill mutation hook. A "Publish to team" button (cloud-upload icon) appears in SkillDetailPanel when canPublish is true, guarded by a confirmation dialog. On success, a toast shows the published version number and any skipped files.

Installing team skills locally

  • Added fetchSkillForInstall to TeamSkillsService, which fetches the latest skill body and resolves every companion file's content in parallel.
  • Added installTeamSkill to SkillsService, which materializes the skill under ~/.claude/skills. Validates the skill name, guards against path traversal in companion file paths, and requires an explicit overwrite: true flag if the skill already exists locally.
  • Wired up an installTeamSkill tRPC procedure and a useInstallTeamSkill mutation hook. An Install/Reinstall button appears in TeamSkillDetailPanel. If the skill already exists, an overwrite confirmation dialog is shown before proceeding.

How did you test this?

  • Added unit tests for TeamSkillsService.publishSkill covering first-publish (create), subsequent publish (version bump), missing description, and unavailable feature.
  • Added unit tests for TeamSkillsService.fetchSkillForInstall verifying that the body and all companion file contents are resolved.
  • Added integration tests for exportSkill verifying frontmatter extraction, companion file collection, binary file skipping, and access denial for non-writable skills.
  • Added integration tests for installTeamSkill covering the happy path, the overwrite guard, invalid skill names, and path traversal rejection.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown

React Doctor could not complete this scan.

No React dependency found in /tmp/react-doctor-baseline-lDddHP/package.json. Add "react" to dependencies (or peerDependencies) and re-run.

Reviewed by React Doctor for commit 12ec1c5.

@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
Fix 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

Comment thread packages/workspace-server/src/services/skills/skills.ts Outdated
Comment thread packages/ui/src/features/skills/TeamSkillDetailPanel.tsx
Comment thread packages/core/src/skills/teamSkillsService.ts Outdated
@k11kirky k11kirky marked this pull request as ready for review June 11, 2026 13:55
Comment thread packages/workspace-server/src/services/skills/skills.ts
Comment thread packages/ui/src/features/skills/useTeamSkillMutations.ts
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
@k11kirky k11kirky force-pushed the posthog-code/skills-06a-team-read branch from 829fa8e to ee58852 Compare June 12, 2026 07:50
@k11kirky k11kirky force-pushed the posthog-code/skills-06b-team-publish branch from a72917a to 975d78b Compare June 12, 2026 07:50
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
@k11kirky k11kirky force-pushed the posthog-code/skills-06b-team-publish branch from 975d78b to eb09670 Compare June 12, 2026 08:19
@k11kirky k11kirky force-pushed the posthog-code/skills-06a-team-read branch from ee58852 to a397721 Compare June 12, 2026 08:19

k11kirky commented Jun 12, 2026

Copy link
Copy Markdown
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
@k11kirky k11kirky force-pushed the posthog-code/skills-06a-team-read branch from a397721 to db84e11 Compare June 12, 2026 11:43
@k11kirky k11kirky force-pushed the posthog-code/skills-06b-team-publish branch from eb09670 to a188d67 Compare June 12, 2026 11:43
@k11kirky k11kirky changed the base branch from posthog-code/skills-06a-team-read to graphite-base/2610 June 12, 2026 12:36
@k11kirky k11kirky changed the base branch from graphite-base/2610 to main June 12, 2026 12:47
k11kirky added 2 commits June 12, 2026 12:48
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
@k11kirky k11kirky force-pushed the posthog-code/skills-06b-team-publish branch from a188d67 to 12ec1c5 Compare June 12, 2026 12:48
@k11kirky k11kirky merged commit ff9c0ad into main Jun 12, 2026
24 checks passed
@k11kirky k11kirky deleted the posthog-code/skills-06b-team-publish branch June 12, 2026 13:01
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
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.

2 participants