SkillsService implements the Agent Skills standard for Emdash. It manages skill installation, catalog aggregation, and symlink synchronization across multiple CLI agents.
Overview
The skills system enables cross-agent reusable skill packages. Each skill is a directory containing aSKILL.md file with YAML frontmatter.
Key features:
- Central storage: Skills stored in
~/.agentskills/{skill-name}/ - Agent sync: Automatic symlink creation to agent-specific directories
- Aggregated catalog: Merges skills from OpenAI, Anthropic, and local sources
- Offline fallback: Bundled catalog for offline use
- Custom skills: Create user-defined skills via UI
- Claude Code:
~/.claude/commands/ - Codex:
~/.codex/skills/ - Amp:
~/.amp/commands/ - OpenCode:
~/.config/opencode/skills/ - Qwen Code:
~/.qwencode/skills/
Central Storage
Directory Structure
Skill Format
SKILL.md example:Initialization
initialize
Ensure the skills directory structure exists.~/.agentskills/(central storage)~/.agentskills/.emdash/(metadata directory)
Catalog Management
getCatalogIndex
Get the aggregated skill catalog (cached or bundled).Unique skill identifier (e.g.,
linear, slack)Human-readable name
Short description
Skill source
GitHub URL (for remote skills)
Icon URL (for remote skills)
Hex color for UI
Default prompt text (OpenAI skills only)
Parsed YAML frontmatter from SKILL.md
Whether skill is installed locally
Absolute path to skill directory (if installed)
Full SKILL.md content (if loaded)
- Return memory cache if available
- Check disk cache (
~/.agentskills/.emdash/catalog-index.json) — use if version matches - Fall back to bundled catalog (
src/main/services/skills/bundled-catalog.json)
refreshCatalog
Fetch the latest catalog from GitHub (OpenAI and Anthropic repos).- Fetches skills from OpenAI repo (
github.com/openai/skills) - Fetches skills from Anthropic repo (
github.com/anthropics/skills) - Deduplicates by skill ID (first occurrence wins)
- Saves to disk cache
- Merges installed state from local directory
Skill Installation
installSkill
Install a skill from the catalog.Skill ID (e.g.,
linear, slack)- Looks up skill in catalog
- Creates temporary directory:
~/.agentskills/{skillId}.tmp-{timestamp} - Downloads
SKILL.mdfrom GitHub (or generates stub) - Atomically renames temp directory to final location
- Syncs skill to all installed agents (creates symlinks)
- Invalidates catalog cache
fs.promises.rename() for atomic move, preventing partial installations.
Example:
uninstallSkill
Uninstall a skill.Skill ID
- Removes symlinks from all agent directories
- Removes skill directory from central storage
- Invalidates catalog cache
createSkill
Create a new custom skill.Skill name (lowercase, alphanumeric, hyphens only, 1-64 chars)
Short description
Optional custom content (inserted after frontmatter)
/^[a-z0-9-]{1,64}$/
Generated SKILL.md:
Agent Synchronization
syncToAgents
Create symlinks for a skill in all installed agent directories.Skill ID
- Checks if each agent’s config directory exists (e.g.,
~/.claude/) - Creates symlink:
{agent-skill-dir}/{skillId}→~/.agentskills/{skillId} - Uses
junctionsymlink type on Windows for compatibility - Removes existing symlink/directory before creating new one
- Claude:
~/.claude/commands/{skillId}→~/.agentskills/{skillId} - Codex:
~/.codex/skills/{skillId}→~/.agentskills/{skillId} - Amp:
~/.amp/commands/{skillId}→~/.agentskills/{skillId} - OpenCode:
~/.config/opencode/skills/{skillId}→~/.agentskills/{skillId} - Qwen:
~/.qwencode/skills/{skillId}→~/.agentskills/{skillId}
unsyncFromAgents
Remove symlinks for a skill from all agent directories.Skill ID
- Only removes symlinks that point to
~/.agentskills/ - Never removes real directories (user-managed skills)
Skill Discovery
getInstalledSkills
Get all locally installed skills (scans central storage and agent directories).~/.agentskills/(central storage)~/.claude/commands/(Claude-specific)~/.codex/skills/(Codex-specific)~/.amp/commands/(Amp-specific)~/.config/opencode/skills/(OpenCode-specific)~/.qwencode/skills/(Qwen-specific)
getSkillDetail
Get full details for a skill (including SKILL.md content).Skill ID
- For installed skills: reads from local disk
- For catalog skills: fetches from GitHub
getDetectedAgents
Detect which CLI agents are installed on the system.Catalog Sources
OpenAI Skills
Repository:github.com/openai/skills
Directories:
skills/.curated/— Curated community skillsskills/.system/— System/built-in skills
agents/openai.yaml in each skill directory:
Anthropic Skills
Repository:github.com/anthropics/skills
Directory: skills/
Metadata:
Parsed from SKILL.md frontmatter:
Bundled Catalog
Location:src/main/services/skills/bundled-catalog.json
Purpose: Offline fallback when GitHub is unreachable.
Update process:
- Run
refreshCatalog()with network access - Copy
~/.agentskills/.emdash/catalog-index.jsontobundled-catalog.json - Commit to repository
Error Handling
Invalid Skill Name
Skill Already Exists
Skill Not Found
Already Installed
Location
Source:src/main/services/SkillsService.ts
Bundled catalog: src/main/services/skills/bundled-catalog.json
Shared types: src/shared/skills/types.ts
Validation: src/shared/skills/validation.ts
Agent targets: src/shared/skills/agentTargets.ts
Singleton export:
Related Services
- ProviderRegistry (
src/shared/providers/registry.ts): Defines CLI agent metadata - SkillsIPC (
src/main/ipc/skillsIpc.ts): IPC handlers for renderer
See Also
- Agent Skills Standard - Official specification
- Skills UI Guide - User-facing skills guide
- Provider Registry - CLI agent definitions