How to Handle Skill Names with Spaces During Installation in the Skills CLI

The Skills CLI automatically converts spaces to hyphens using the sanitizeName() function in src/installer.ts, allowing safe filesystem storage without manual intervention.

Users can install skills with descriptive names containing spaces directly from the command line. The Skills CLI, developed by Vercel Labs, handles the conversion internally through a robust sanitization pipeline that ensures predictable, secure directory creation.

How the Skills CLI Sanitizes Names with Spaces

The Core Sanitization Function

The transformation happens in src/installer.ts at lines 40-53. The sanitizeName() function processes every skill name before any filesystem operation:

export function sanitizeName(name: string): string {
  const sanitized = name
    .toLowerCase()
    // Replace any sequence of characters that are NOT lowercase letters (a-z),
    // digits (0-9), dots (.) or underscores (_) with a single hyphen.
    // This converts spaces, special chars, and path-traversal attempts (../) into hyphens.
    .replace(/[^a-z0-9._]+/g, '-')
    // Remove leading/trailing dots and hyphens to prevent hidden files (.) and
    // ensure clean directory names.
    .replace(/^[.\-]+|[.\-]+$/g, '');
  // Limit to 255 chars (common filesystem limit), fallback to 'unnamed-skill' if empty
  return sanitized.substring(0, 255) || 'unnamed-skill';
}

What Happens to Spaces

The regex /[^a-z0-9._]+/g treats spaces as disallowed characters, collapsing them into single hyphens:

Input Name Sanitized Output
my cool skill my-cool-skill
My Cool Skill my-cool-skill
my cool skill my-cool-skill

Space Handling in the Installation Pipeline

The installSkillForAgent function in src/installer.ts demonstrates the complete flow:

const sanitized = sanitizeName(skillName);
const skillDir = join(targetBase, sanitized);

This guarantees that skill names with spaces never reach the filesystem in their raw form.

Installing Skills with Spaces from the Command Line

Direct CLI Usage

Users can pass space-containing names directly via the --skill flag:

npx skills add vercel-labs/agent-skills --skill "my cool skill"

The CLI in src/add.ts (lines 172-186) parses the argument and forwards it to the installer unchanged. The raw name is preserved for display purposes while the sanitized version creates the directory.

Expected Output

After installation, the CLI summarizes the result:


Installation Summary
/home/user/.agents/skills/my-cool-skill
  universal: Claude, CodeBuddy, ...

Edge Cases and Safety Guarantees

Character-Specific Transformations

Situation Result Prevention Mechanism
" Leading and trailing " leading-and-trailing Leading/trailing hyphens stripped via `/^[.-]+
"C++ Helper" c-helper + characters collapsed to hyphens
"../escape" escape Path-traversal characters neutralized
"🚀 rocket" rocket Non-ASCII characters filtered out

Filesystem Safety Limits

The sanitizeName() function enforces a 255-character maximum and provides a fallback for empty results:

return sanitized.substring(0, 255) || 'unnamed-skill';

Programmatic Usage with Space-Containing Names

Node.js API Example

import { installSkillForAgent } from './src/installer.ts';
import { agents } from './src/agents.ts';

async function install() {
  const skillName = 'my cool skill'; // any user-provided string with spaces
  const result = await installSkillForAgent(
    { name: skillName, files: new Map() }, // minimal Skill object
    'claude-code',                         // target agent
    { global: false, mode: 'copy' }
  );

  console.log('Installed to:', result.path);
  // Output: Installed to: /home/user/.agents/skills/my-cool-skill
}

install();

Verifying the Sanitized Directory


# After installation, confirm the space-to-hyphen conversion

ls ~/.agents/skills | grep my-cool-skill

# → my-cool-skill

Key Source Files

File Purpose Lines
src/installer.ts Defines sanitizeName() and installSkillForAgent() 40-53, 90-120
src/add.ts Parses CLI --skill arguments and forwards to installer 172-186
src/skill-lock.ts Stores original unsanitized names for future updates 1-30
src/types.ts Skill type definition with name field 1-20

Summary

  • Automatic transformation: The sanitizeName() function in src/installer.ts converts all spaces to hyphens before any filesystem operation.
  • Safe CLI usage: Pass skill names with spaces directly to npx skills add --skill "name with spaces" — no manual escaping required.
  • Consistent output: All sanitized names follow kebab-case, lowercase, with path-traversal protection and 255-character limits.
  • Original name preservation: The unsanitized name is retained in src/skill-lock.ts for display and update purposes.

Frequently Asked Questions

What happens if I install two skills with similar names like "my skill" and "My Skill"?

Both names sanitize to my-skill, causing the second installation to overwrite or conflict with the first. The CLI's case normalization in sanitizeName() treats these as identical. Use distinct base names to avoid collisions.

Can I prevent the automatic space-to-hyphen conversion?

No — the sanitization in src/installer.ts is mandatory for all skill names. This design prevents filesystem errors, path traversal attacks, and cross-platform compatibility issues. The original name with spaces is preserved in the skill lock file for display purposes.

How does the CLI handle skill names with emojis or special Unicode characters?

Emojis and non-ASCII characters are removed during sanitization. The regex /[^a-z0-9._]+/g only permits lowercase letters, digits, dots, and underscores. A name like "🚀 rocket" becomes rocket, and "naïve" becomes na-ve after the ï is replaced with a hyphen.

Where can I see the original name with spaces after installation?

Check the skill lock file at .agents/skills-lock.json (or your configured lock file location). The src/skill-lock.ts module stores the unsanitized name property alongside the sanitized directory name, enabling accurate updates and user-friendly CLI output.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →