How experimental_sync Integrates with node_modules in the Skills CLI
The experimental_sync command scans your project's node_modules directory for skills bundled as npm packages, then installs them into canonical agent skill directories with symlinks to your selected agents.
The experimental_sync command in the Vercel Labs Skills CLI bridges the gap between npm-distributed skills and local agent configurations. This experimental feature enables developers to treat skills as versioned dependencies while automatically wiring them into agent-specific skill directories. Understanding how this command discovers, validates, and installs skills from node_modules helps you manage complex multi-agent workflows efficiently.
How experimental_sync Discovers Skills in node_modules
The discovery phase begins in src/sync.ts with the discoverNodeModuleSkills function. This crawler treats your node_modules directory as a searchable registry of potential skills.
Discovery Algorithm
The function performs the following operations:
- Reads the directory structure using
readdir, skipping hidden entries and standard npm artifacts - Handles scoped packages (
@org/pkg) by descending into organization directories - Searches multiple locations within each package for skill definitions:
Each discovered skill returns a structured object with name, description, path, and packageName properties.
// Conceptual extraction from src/sync.ts
interface DiscoveredSkill {
name: string;
description: string;
path: string; // Absolute path to skill directory
packageName: string; // Source npm package
}
Lock File Comparison and Change Detection
After discovery, experimental_sync consults the local lock file to avoid redundant installations.
Lock File Mechanics
The readLocalLock function in src/local-lock.ts parses skills-lock.json (project-scoped) or ~/.agents/.skill-lock.json (global). This file stores cryptographic hashes of previously installed skill directories.
The runSync function (lines 71-84 in src/sync.ts) implements the change detection logic:
// Pseudocode from src/sync.ts → runSync
if (force) {
toInstall = allDiscoveredSkills;
} else {
toInstall = allDiscoveredSkills.filter(skill => {
const currentHash = computeSkillFolderHash(skill.path);
const lockedHash = localLock.get(skill.name);
return currentHash !== lockedHash; // True if new or changed
});
}
The --force (-f) flag bypasses this optimization for complete reinstallation.
Agent Selection and Targeting
Once the installation candidate list is determined, experimental_sync resolves which agents should receive the skills.
Agent Resolution Logic
The runSync function (lines 98-140 in src/sync.ts) handles this through several pathways:
| Scenario | Behavior |
|---|---|
--agent specified |
Validates provided agent names against known agents |
| No agents installed | Defaults to universal agents (those sharing .agents/skills) |
| Agents installed + interactive mode | Launches searchMultiselect prompt from src/prompts/search-multiselect.ts |
-y flag present |
Auto-confirms default agent selection |
Universal agents—identified via getUniversalAgents in src/agents.ts—don't require symlinks because they already reference the canonical skill directory.
Installation and Symlink Creation
The actual installation delegates to installSkillForAgent in src/installer.ts, which performs filesystem operations with fallback safety mechanisms.
Installation Pipeline
// Conceptual flow from src/installer.ts
function installSkillForAgent(skill, agent, options) {
const sanitizedName = sanitizeName(skill.name);
const canonicalDir = getCanonicalSkillsDir(options.global);
// 1. Create canonical location
const skillCanonicalPath = path.join(canonicalDir, sanitizedName);
copyDirectory(skill.path, skillCanonicalPath);
// 2. Handle universal agents (skip symlink)
if (isUniversalAgent(agent) && options.global) {
return { installed: true, symlink: false };
}
// 3. Create agent-specific symlink or copy
const agentSkillPath = getAgentSkillPath(agent, sanitizedName);
try {
createSymlink(skillCanonicalPath, agentSkillPath);
return { installed: true, symlink: true };
} catch (error) {
// Fallback: copy when symlinks fail (Windows, etc.)
copyDirectory(skillCanonicalPath, agentSkillPath);
return { installed: true, symlink: false, fallback: 'copy' };
}
}
The canonical directory defaults to .agents/skills (project-scoped) or ~/.agents/skills (with --global). The createSymlink function handles cross-platform differences, falling back to full copies when symbolic links are unavailable or permission-restricted.
Lock File Update and Telemetry
Post-installation, experimental_sync finalizes its operation with state persistence and analytics.
Finalization Steps
- Hash recomputation:
computeSkillFolderHashregenerates the cryptographic digest of the installed skill directory - Lock entry writing:
addSkillToLocalLockinsrc/local-lock.tspersists the new state toskills-lock.json - Telemetry emission: The
trackfunction sends an anonymousexperimental_syncevent containing:- Count of successfully installed skills
- Count of failed installations
- Names of targeted agents
Common Commands for experimental_sync
| Command | Purpose |
|---|---|
skills experimental_sync |
Interactive sync with agent selection prompt |
skills experimental_sync -y |
Auto-confirm agent selection for CI/CD |
skills experimental_sync -f |
Force reinstall all discovered skills |
skills experimental_sync -a cursor claude-code |
Target specific agents only |
skills experimental_sync --global |
Use global canonical directory (~/.agents/skills) |
Key Source Files Reference
| File | Responsibility |
|---|---|
src/sync.ts |
Command orchestration, discovery, UI, lock handling, telemetry |
src/installer.ts |
File operations: canonical copy, symlinking, fallback copies |
src/agents.ts |
Agent definitions, universal agent detection, path resolution |
src/local-lock.ts |
Lock file I/O and hash-based change detection |
src/constants.ts |
Path constants: AGENTS_DIR, SKILLS_SUBDIR |
src/prompts/search-multiselect.ts |
Interactive agent selection UI |
Summary
experimental_syncdiscovers skills by crawlingnode_modulesforSKILL.mdfiles and conventional skill subdirectories- Change detection via
skills-lock.jsonprevents redundant installations unless--forceis used - Agent targeting supports explicit selection, interactive prompts, or automatic universal agent assignment
- Installation uses a canonical-symlink pattern: skills copy to
.agents/skills/or~/.agents/skills/, then symlink to agent-specific directories with copy fallback - Cross-platform compatibility handles Windows symlink limitations through automatic copy fallback
Frequently Asked Questions
What file pattern does experimental_sync use to identify skills in node_modules?
The command searches for SKILL.md files in multiple locations within each package: the package root, a skills/ subdirectory, a .agents/skills/ subdirectory, and any nested folder containing a SKILL.md. This convention-based discovery allows skills to be bundled as standard npm packages without custom metadata.
How does experimental_sync handle skills that are already installed?
The command computes a cryptographic hash of each discovered skill's directory and compares it against entries in skills-lock.json. Skills with matching hashes are skipped unless you pass the --force flag, which bypasses the lock file and reinstalls all discovered skills regardless of their current state.
What happens when symlinking fails during installation?
The installSkillForAgent function in src/installer.ts attempts to create a symbolic link from the agent's skill directory to the canonical location. If this fails—common on Windows without developer mode or elevated permissions—it automatically falls back to a full directory copy, ensuring the skill is always available to the agent.
Can I use experimental_sync in CI/CD pipelines without interactive prompts?
Yes. Pass the -y flag to auto-confirm agent selection, or use -a <agent1> <agent2> to explicitly specify target agents. Combine with --global if your CI environment requires skills in a centralized location. The -f flag ensures fresh installations regardless of lock state.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →