ccski is a CLI + MCP server to discover, install, enable/disable, and serve Claude/Codex-compatible skills. It also exports a small “kernel” API so you can embed discovery/validation in your own scripts. This README covers install and usage. For architecture and UX philosophy, see SPEC.md.
Documentation site: https://jixoai-labs.github.io/ccski/
Requires Node.js >= 20.
# run directly
npx ccski --help
# or install locally
pnpm install ccski
ccski --helpccski works best when your agent is told how to discover local skills at the start of a new context. The installer writes a managed English workflow block into common agent instruction files:
npx -y ccski installBy default this installs at user scope for known agents:
- Codex:
~/.codex/AGENTS.md - Claude Code:
~/.claude/CLAUDE.md - Gemini CLI:
~/.gemini/GEMINI.md - OpenCode:
~/.config/opencode/AGENTS.md
Limit the target or install only into the current project:
# one agent, user scope
npx -y ccski install --agent=codex
# one project file in the current directory
npx -y ccski install --agent=gemini --project
# preview changes
npx -y ccski install --dry-run --jsonThe installer is idempotent. It replaces only the managed
<workflow name="ccski">...</workflow> block and preserves the rest of your
prompt file.
Manual install is also fine. Add this block to your user or project instruction
file, such as ~/.codex/AGENTS.md, ~/.claude/CLAUDE.md, or
~/.gemini/GEMINI.md:
<workflow name="ccski">
When starting a new context, run `bunx ccski list --no-color` to discover extra local skills available on this machine, especially shared `agents:user` skills and agent-specific skills such as `claude:user`, `codex:user`, and `gemini:user`.
If the user names a skill, or a task clearly matches a skill that is not already exposed in the current session, do not assume the skill is unavailable. First run `bunx ccski list --no-color`, then run `bunx ccski info <name>` and load the `SKILL.md` path reported by the output.
`ccski` may emit compatibility warnings while reading local agent or plugin metadata, such as `installed_plugins.json`. These warnings do not necessarily block `list` or `info`; prefer `--no-color` for readable output and downstream parsing.
</workflow>npx ccski mcp- Add extra skill roots:
npx ccski mcp --skill-dir /extra/skills - Disable auto refresh:
npx ccski mcp --no-refresh
MCP plugin config example (Codex/Cursor/Windsurf/VS Code):
{
"mcpServers": {
"ccski": {
"command": "npx",
"args": ["ccski", "mcp"]
}
}
}| Command | Purpose |
|---|---|
ccski list |
List discovered skills (project, user, plugin) |
ccski info <name> |
Show metadata and content preview |
ccski install |
Install the ccski workflow block into agent instruction files |
ccski install <source> [-i|--all|--path] |
Install from git/dir/marketplace/SKILL.md; interactive picker available |
ccski enable [names...] [-i|--all] |
Enable skills (.SKILL.md -> SKILL.md) |
ccski disable [names...] [-i|--all] |
Disable skills (SKILL.md -> .SKILL.md) |
ccski validate <path> |
Validate SKILL.md or skill directory |
ccski mcp |
Start MCP server (stdio/http/sse) |
- Git repo (auto-detect marketplace):
ccski install https://github.com/wshobson/agents - Specific branch or path:
ccski install https://github.com/wshobson/agents/tree/main --branch mainccski install https://github.com/wshobson/agents --path skills/foo/SKILL.md - Local directory or single file:
ccski install /path/to/skills --mode fileccski install ./plugins/foo/SKILL.md - Overwrite existing skill: add
--force(or--override).
# Enable via interactive picker
ccski enable -i
# Disable all enabled skills
ccski disable --allBy default ccski scans shared and agent-specific skill roots in the workspace and user
home directory. Built-in agent roots include .claude/skills, .codex/skills,
.gemini/skills, and .openclaw/skills; ccski also discovers shallow dynamic
agent roots such as .<agent>/skills.
When auto selection sees the same skill name in multiple roots, ccski keeps every
copy internally but chooses one by source priority:
--skill-dircustom roots<workspace>/.<agent>/skills<workspace>/.agents/skills<workspace>/skills~/.<agent>/skills~/.agents/skills- Claude plugin skills
If two copies have the same source priority, the newer SKILL.md or .SKILL.md
mtime wins. If mtimes also tie, provider ordering is deterministic.
- Programmatic API is available from the package export; see API Reference (or the docs site) for usage examples.
- Claude users: prefer
ccski mcp --exclude=claudeto avoid echoing built-in Claude skills. - Codex users: prefer
ccski mcp --exclude=codexwhen avoid echoing built-in Codex skills. - All commands support
--jsonfor scripting. - Use
--no-colorto disable colors or--colorto force them. - Read
SPEC.mdfor deep technical details and design philosophy.
- openskills — established the SKILL.md authoring pattern; ccski aligns with that spec.
- universal-skills — MCP-first skill set; ccski focuses on management, not bundling content.
Public exports from import ... from "ccski".
Notes:
- Package is ESM (
"type": "module"). Useimportin Node.js >= 20. discoverSkills()/SkillRegistry.getAll()return metadata. UseloadSkill()/SkillRegistry.load()to read full SKILL.md content.
import { discoverSkills, SkillRegistry, validateSkillFile } from "ccski";
import type { Skill, SkillMetadata } from "ccski";SkillProvider: built-ins"agents" | "claude" | "codex" | "gemini" | "openclaw" | "file"plus discovered.<agent>/skillsprovidersSkillLocation:"user" | "project" | "plugin"SkillFrontmatter: required SKILL.md frontmatter shape (name,description, plus extra fields)SkillMetadata: discovered skill summary (name/description/provider/location/path + bundled resources flags)Skill:SkillMetadata+content(full markdown, including frontmatter) +fullNameParseResult:{ frontmatter, content, fullContent }DiscoveryOptions: configure default roots, custom directories, provider tagging, and disabled-skill handlingSkillRegistryOptions:DiscoveryOptions+ plugin discovery options (pluginsFile,pluginsRoot,settingsFile,userDir)
Reference shapes (simplified):
export interface SkillMetadata {
name: string;
description: string;
disabled?: boolean;
provider: "claude" | "codex" | "file";
location: "user" | "project" | "plugin";
path: string;
hasReferences: boolean;
hasScripts: boolean;
hasAssets: boolean;
pluginInfo?: { pluginName: string; marketplace: string; version: string };
}
export interface Skill extends SkillMetadata {
content: string; // full markdown (including frontmatter)
fullName: string;
}All errors extend CcskiError and include a suggestions: string[] field for UX-friendly guidance.
SkillNotFoundError: thrown when a skill name cannot be resolvedAmbiguousSkillNameError: thrown when multiple skills match; includesmatches: string[]ParseError: SKILL.md read/UTF-8/frontmatter parsing failures; includesfilePath,reasonValidationError: frontmatter schema validation failures; includesfilePath,issues: string[]
Parse a SKILL.md (or .SKILL.md) file and return:
frontmatter: validated & normalized (descriptionwhitespace is normalized)content: markdown body without frontmatterfullContent: original file content including frontmatter
Throws ParseError (IO/encoding/YAML) and ValidationError (schema).
Safe validator wrapper around parseSkillFile():
success: truewhen file is valid- otherwise returns
errorsandsuggestionswithout throwing
import { validateSkillFile } from "ccski";
const result = validateSkillFile("/abs/path/to/SKILL.md");
if (!result.success) {
console.error(result.errors);
console.error(result.suggestions);
}Return the default search roots (project + user) with provider tagging (Claude/Codex).
Scan built-in directories (unless scanDefaultDirs: false) plus customDirs.
skills:SkillMetadata[]diagnostics: scanned paths, warnings, conflicts, and counts by provider
import { discoverSkills } from "ccski";
const { skills, diagnostics } = discoverSkills({
includeDisabled: true,
customDirs: ["/extra/skills"],
customProvider: "file",
});Load a discovered skill’s full content (reads SKILL.md or .SKILL.md based on metadata.disabled).
Lower-level scanner used by discoverSkills(). Useful when you want full control over:
- root path + recursion
- provider tagging (
"claude" | "codex" | "file") - optional
scopeprefixing for names
Convenience wrapper around discovery + fuzzy resolution.
import { SkillRegistry } from "ccski";
const registry = new SkillRegistry({ includeDisabled: true });
const all = registry.getAll(); // SkillMetadata[]
const full = registry.load("some-skill"); // Skill (with content)Methods:
refresh(): rescan directories (and plugins unlessskipPlugins: true)getAll(): list all discovered skillsfind(name): resolve a name (case-insensitive, supports short name andprovider:name)has(name): boolean existence checkload(name): resolve + read full contentgetDiagnostics(): totals + scanned roots + warnings/conflicts
These are exported for validating/parsing external JSON and frontmatter in a type-safe way:
SkillFrontmatterSchema/SkillFrontmatterTypePluginEntrySchema/PluginEntryTypeInstalledPluginsSchema/InstalledPluginsTypeClaudeSettingsSchema/ClaudeSettingsType