How the Skills CLI Agent Detection Mechanism Works: A Deep Dive into `vercel-labs/skills`
The Skills CLI detects installed agents by checking for unique marker directories or files on the filesystem, using a configurable detection map defined in src/agents.ts.
The vercel-labs/skills repository provides a CLI tool for managing shared skills across multiple AI agent platforms. A critical capability of this tool is its agent detection mechanism—the ability to automatically discover which agent runtimes (AMP, OpenClaw, Claude Code, etc.) are present on a user's machine. This article explains exactly how this detection system works, with complete source code references.
The Two-Step Agent Detection Architecture
The Skills CLI implements agent detection through a clean separation between configuration and execution. This design allows easy extension for new agents without modifying core detection logic.
Step 1: Per-Agent Configuration with detectInstalled Functions
Each supported agent is defined in src/agents.ts with a detectInstalled async function that checks for a filesystem marker unique to that agent:
// From src/agents.ts (conceptual structure)
const agents = {
openclaw: {
detectInstalled: async () => {
return fs.existsSync(path.join(os.homedir(), '.openclaw'));
}
},
gemini: {
detectInstalled: async () => {
return fs.existsSync(path.join(os.homedir(), '.gemini', 'antigravity'));
}
},
augment: {
detectInstalled: async () => {
return fs.existsSync(path.join(os.homedir(), '.augment'));
}
}
// ... additional agents
};
The detection checks use Node.js fs.existsSync for synchronous filesystem presence verification. Each agent targets a distinctive marker:
| Agent | Marker Path | Detection Strategy |
|---|---|---|
| OpenClaw | ~/.openclaw |
Hidden directory in home folder |
| Gemini | ~/.gemini/antigravity |
Nested file within hidden directory |
| Augment | ~/.augment |
Hidden directory in home folder |
Step 2: Aggregation with detectInstalledAgents()
The detectInstalledAgents() function in src/agents.ts (lines 41-48) orchestrates the complete detection process:
// From src/agents.ts
export async function detectInstalledAgents(): Promise<AgentType[]> {
const results = await Promise.all(
Object.entries(agents).map(async ([key, config]) => {
const isInstalled = await config.detectInstalled();
return isInstalled ? (key as AgentType) : null;
})
);
return results.filter((agent): agent is AgentType => agent !== null);
}
This function:
- Iterates over all entries in the
agentsmap - Executes each
detectInstalledfunction in parallel viaPromise.all - Filters to return only the
AgentTypevalues for successfully detected agents
How Commands Use Agent Detection
The agent detection mechanism integrates directly into CLI workflows. Here's how key commands leverage it:
The add Command: Auto-Selection of Installed Agents
In src/add.ts (lines 36-42), the detection results populate the interactive UI:
// From src/add.ts
const installedAgents = await detectInstalledAgents();
// Auto-select detected agents + ensure universal agents are always included
// Universal agents share the .agents/skills folder and are always active
This enables a seamless experience where users see only relevant agents pre-selected.
The remove Command: Targeted Cleanup
The remove command in src/remove.ts uses detection to determine which agent directories need symlink cleanup, avoiding errors from attempting operations on non-existent installations.
The sync Command: Conditional Synchronization
In src/sync.ts, agent detection precedes global skill directory synchronization, ensuring sync operations only target installed agent environments.
Type Definitions Supporting Detection
The src/types.ts file establishes the TypeScript contracts that enable type-safe agent detection:
// From src/types.ts
export type AgentType =
| 'openclaw'
| 'gemini'
| 'augment'
| 'amp'
| 'claude'
| 'universal';
export interface AgentConfig {
name: string;
description: string;
detectInstalled: () => Promise<boolean>;
skillsDir: string;
// ... additional configuration
}
These types ensure that:
- Only valid
AgentTypevalues can be returned from detection - Every agent configuration implements the required
detectInstalledcontract
Advantages of This Detection Approach
The Skills CLI's agent detection mechanism offers several architectural benefits:
- Extensibility: Adding new agents requires only a new entry in
src/agents.tswith a unique marker path - Reliability: Filesystem-based detection is deterministic and doesn't depend on process enumeration
- Performance:
Promise.allparallelization ensures all checks complete quickly - Portability: Works across macOS, Linux, and Windows (via Node.js path normalization)
- Maintainability: Detection logic is centralized and testable
Summary
The Skills CLI implements agent detection through a two-layer system:
- Configuration layer: Each agent in
src/agents.tsdefines adetectInstalledfunction that checks for a unique filesystem marker - Aggregation layer: The
detectInstalledAgents()function runs all checks in parallel and returns installed agent types
This mechanism powers automatic agent selection in commands like add, remove, and sync, while maintaining extensibility for new agent platforms.
Frequently Asked Questions
How does the Skills CLI detect Claude Code installation?
The Skills CLI detects Claude Code by checking for a marker directory or file specific to that agent's installation, as defined in the agents map within src/agents.ts. Each agent uses a unique filesystem path—typically within the user's home directory—that indicates the agent's presence.
Can I add support for a custom agent to the Skills CLI?
Yes, the detection architecture in src/agents.ts is designed for extensibility. You would add a new entry to the agents map with a detectInstalled function that checks for your custom agent's unique marker file or directory, plus the required AgentConfig properties for skill directory paths and display information.
Why does the Skills CLI use filesystem markers instead of process detection?
Filesystem markers provide reliable, deterministic detection without requiring runtime process enumeration or environment parsing. According to the vercel-labs/skills source code, this approach works across platforms, avoids false positives from transient processes, and integrates cleanly with the CLI's async initialization flow using fs.existsSync checks.
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 →