Skip to content

feat(sync): install git sources from package.json skills fields - #2403

Merged
antfu merged 1 commit into
vercel-labs:mainfrom
antfubot:feat/sync-remote-entries
Oct 9, 2026
Merged

antfu merged 1 commit into
vercel-labs:mainfrom
antfubot:feat/sync-remote-entries

Conversation

@antfubot

@antfubot antfubot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Step 7 of #2323 (RFC: Install skills from npm packages). Builds on #2400 (field parsing), #2401 (programmatic install primitives) and #2402.

What changes

skills experimental_sync now installs git sources listed in package.json skills fields. This is what makes a skills pack work:

{
  "name": "@antfu/skills",
  "skills": [
    "vercel-labs/agent-browser",
    "vercel-labs/agent-skills#v1.4.0@web-design-guidelines",
    { "source": "antfu/skills", "ref": "v2", "skills": ["vue", "vitest"] },
    "npm:@acme/docs"
  ]
}

A project that depends on this pack gets all of these skills on skills experimental_sync. This is the same as running skills add for each entry, except that the list comes from the installed packages.

Grammar

Remote entries are parsed with the CLI's own parseSource, so owner/repo, owner/repo@skill, #ref, #ref@skill, /tree/<ref>/<path> URLs, GitLab URLs and git@/https git URLs all work, as in skills add.

Per the skills-npm SPEC:

  • Only git-hosted sources are allowed. Local paths, well-known URLs and direct downloads are errors.
  • A ref on a source that already carries one (#ref or /tree/<ref>/) is an error.
  • An @skill shorthand is added to the entry's skills list.
  • Identical requests (same URL, ref, subpath and skill list) from several packages are installed once, as SPEC rule 2 requires.

The error rules from step 5 apply: the project's own field stops sync, and a dependency's field only warns.

Installing

Sync calls installFromSource in-process. That is the primitive from #2401. It now:

  • takes a ParsedSource, so the object form's ref can apply
  • records via in the lock
  • accepts a select hook that drops skills before installing

Conflict handling:

  • A skill shipped by a dependency, or provided by an earlier source in the same run, wins over a remote one with the same name. A shipped skill also replaces a remote skill installed earlier.
  • A skill installed with skills add is never shadowed.
  • A directory that sync does not own is never replaced.

Sync now owns any lock entry it wrote: sourceType: 'node_modules' or a via. Rules 1 and 2 are shared between shipped and remote skills through blockedReason.

Already installed

A request whose skills are already in the lock (same source, ref and via) and on disk is not fetched again, so a prepare run with nothing to do needs no network. skills update refreshes those skills, because they are ordinary github/gitlab/git lock entries.

Cleanup and flags

Remote skills that no field requests anymore are removed by the step 3 cleanup, using the same ownership rule. --no-remote skips remote entries for both installing and removing, which is useful offline.

A failing source is reported, the rest of the run continues, and the exit code is 1.

Tests

  • tests/skills-field.test.ts covers git sources with @skill and ref folded in, GitLab /-/tree/, rejection of non-git sources, and rejection of a double ref.
  • tests/sync.test.ts adds a remote skills field entries group. It runs offline against a local git repository through file://:
    • install from the project's field and from a pack's field (with via)
    • the object-entry skill filter
    • no refetch once installed (the repository is deleted before the second run), and a reinstall when the skill folder is gone
    • removal when no field requests a skill anymore
    • --no-remote
    • a shipped skill beating a remote one
    • a skills add skill not shadowed
    • a failing source with exit code 1 while shipped skills still install
    • a non-git root entry rejected

The full suite passes (953).


This PR was created with the help of an agent.

@vercel-security-reviewer

Copy link
Copy Markdown

Security review details

@vercel-agent-factory vercel-agent-factory Bot added the enhancement New feature or request label Oct 7, 2026
@antfubot
antfubot force-pushed the feat/sync-remote-entries branch from 1f9ca3f to 6fe8278 Compare October 7, 2026 07:12
Remote entries in a skills field (owner/repo, owner/repo@skill,
installed by experimental_sync. Only git-hosted sources are allowed;
local paths and plain URLs are errors, as in the skills-npm SPEC.
Identical requests from several packages are installed once.

Sync installs them in-process with installFromSource, which now takes
a parsed source, records via in the lock, and lets the caller drop
skills before installing. A skill shipped by a dependency or an earlier
source wins, a skill installed with skills add is never shadowed, and a
directory sync does not own is never replaced.

A request whose skills are already in the lock and on disk is not
fetched again; skills update refreshes them. Remote skills that no
field requests anymore are removed. --no-remote skips remote entries
for both installing and removing. A failing source is reported, the
rest of the run continues, and the exit code is 1.
@antfubot
antfubot force-pushed the feat/sync-remote-entries branch from 6fe8278 to e8cce15 Compare October 9, 2026 02:26
@antfu
antfu merged commit c75f604 into vercel-labs:main Oct 9, 2026
10 checks passed
@antfu antfu mentioned this pull request Oct 9, 2026
7 of 10 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants