# Skilldeck

> Manage AI agent skills via natural language — install, update, delete, and assign skills to agents using SkillDeck's filesystem conventions.

- **Type:** Skill
- **Install:** `agentstack add skill-crossoverjie-skilldeck-skilldeck`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [crossoverJie](https://agentstack.voostack.com/s/crossoverjie)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [crossoverJie](https://github.com/crossoverJie)
- **Source:** https://github.com/crossoverJie/SkillDeck/tree/main/skills/skilldeck
- **Website:** http://crossoverjie.top/SkillDeck/

## Install

```sh
agentstack add skill-crossoverjie-skilldeck-skilldeck
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# SkillDeck Manager

Manage AI coding agent skills through natural language. This skill teaches you how to install, update, delete, and assign skills using SkillDeck's filesystem conventions.

SkillDeck is a macOS GUI app that manages skills across 14 AI agents. Skills are stored as directories containing `SKILL.md` files. This skill lets you perform the same operations from the terminal.

## Filesystem Layout

```
~/.agents/
├── skills/                    # Canonical storage (real files live here)
│   ├── my-skill/
│   │   ├── SKILL.md           # Skill definition (YAML frontmatter + markdown)
│   │   └── ...                # Other files (scripts, templates, etc.)
│   └── another-skill/
│       └── SKILL.md
├── .skill-lock.json           # Lock file (v3, shared with npx skills)
└── .skilldeck-cache.json      # SkillDeck's private cache (do not modify)

~/.claude/skills/              # Claude Code skills (symlinks → canonical)
~/.codex/skills/               # Codex skills (symlinks → canonical, also reads ~/.agents/skills/)
~/.gemini/skills/              # Gemini CLI skills
~/.copilot/skills/             # Copilot CLI skills (also reads ~/.claude/skills/)
~/.config/opencode/skills/     # OpenCode skills (also reads ~/.claude/skills/ and ~/.agents/skills/)
~/.cursor/skills/              # Cursor skills (also reads ~/.claude/skills/)
~/.kiro/skills/                # Kiro skills
~/.codebuddy/skills/           # CodeBuddy skills
~/.openclaw/skills/            # OpenClaw skills
~/.trae/skills/                # Trae skills
~/.qoder/skills/               # Qoder skills
~/.qclaw/skills/               # QClaw skills
~/.workbuddy/skills/           # WorkBuddy skills
~/.gemini/antigravity/skills/  # Antigravity skills
```

**Key rules:**
- The real copy of every skill lives in `~/.agents/skills//`
- Each agent gets a **symlink** pointing to the canonical directory
- Example: `~/.claude/skills/my-skill` → `~/.agents/skills/my-skill`
- Some agents can read other agents' directories (cross-directory inheritance):
  - **Codex** reads `~/.agents/skills/` natively (no symlink needed)
  - **Copilot** reads `~/.claude/skills/`
  - **OpenCode** reads `~/.claude/skills/` and `~/.agents/skills/`
  - **Cursor** reads `~/.claude/skills/`

## Default Agent Configuration

When installing a skill, you need to decide which agents to assign it to. The recommended approach:

1. **Auto-detect installed agents** — check which CLI commands exist on the system
2. **Assign to all detected agents** — unless the user specifies a subset

The following script detects installed agents and builds a list of their skills directories:

```bash
# Agent detection map: CLI command → skills directory
declare -A AGENT_DIRS=(
  ["claude"]="$HOME/.claude/skills"
  ["codex"]="$HOME/.codex/skills"
  ["gemini"]="$HOME/.gemini/skills"
  ["opencode"]="$HOME/.config/opencode/skills"
  ["antigravity"]="$HOME/.gemini/antigravity/skills"
  ["cursor"]="$HOME/.cursor/skills"
  ["kiro"]="$HOME/.kiro/skills"
  ["codebuddy"]="$HOME/.codebuddy/skills"
  ["openclaw"]="$HOME/.openclaw/skills"
  ["trae"]="$HOME/.trae/skills"
  ["qoder"]="$HOME/.qoder/skills"
  ["qclaw"]="$HOME/.qclaw/skills"
  ["workbuddy"]="$HOME/.workbuddy/skills"
)

# Detect which agents are installed
INSTALLED_DIRS=()
for CMD in "${!AGENT_DIRS[@]}"; do
  if which "$CMD" &>/dev/null; then
    INSTALLED_DIRS+=("${AGENT_DIRS[$CMD]}")
    echo "Detected: $CMD → ${AGENT_DIRS[$CMD]}"
  fi
done

# Copilot CLI is a GitHub CLI extension (gh copilot), not a standalone binary.
# `which gh` only confirms GitHub CLI is installed, not Copilot specifically.
# Check for the copilot extension explicitly.
if which gh &>/dev/null && gh extension list 2>/dev/null | grep -q copilot; then
  INSTALLED_DIRS+=("$HOME/.copilot/skills")
  echo "Detected: copilot → $HOME/.copilot/skills"
fi

echo "Found ${#INSTALLED_DIRS[@]} installed agents"
```

Use `INSTALLED_DIRS` as the default target when installing. If the user says "only install for Claude Code", filter to just `$HOME/.claude/skills`.

## Lock File Format

Location: `~/.agents/.skill-lock.json` (version 3)

```json
{
  "version": 3,
  "skills": {
    "skill-name": {
      "source": "owner/repo",
      "sourceType": "github",
      "sourceUrl": "https://github.com/owner/repo.git",
      "skillPath": "skills/skill-name/SKILL.md",
      "skillFolderHash": "abc123...",
      "installedAt": "2024-01-01T00:00:00Z",
      "updatedAt": "2024-01-01T00:00:00Z"
    }
  },
  "dismissed": {},
  "lastSelectedAgents": []
}
```

**Fields:**
- `source`: Repository identifier (e.g., `"crossoverJie/skills"`) or local path
- `sourceType`: `"github"`, `"local"`, or `"clawhub"`
- `sourceUrl`: Full git URL
- `skillPath`: Relative path to SKILL.md within the source
- `skillFolderHash`: Git tree hash for update detection (can be empty string for local)
- `installedAt` / `updatedAt`: ISO 8601 timestamps

## Helper Functions

These reusable snippets are referenced in the operations below.

### List all agent skills directories

```bash
# All 14 agent skills directories (for symlink scanning)
ALL_AGENT_SKILLS=(
  "$HOME/.claude/skills"
  "$HOME/.codex/skills"
  "$HOME/.gemini/skills"
  "$HOME/.copilot/skills"
  "$HOME/.config/opencode/skills"
  "$HOME/.gemini/antigravity/skills"
  "$HOME/.cursor/skills"
  "$HOME/.kiro/skills"
  "$HOME/.codebuddy/skills"
  "$HOME/.openclaw/skills"
  "$HOME/.trae/skills"
  "$HOME/.qoder/skills"
  "$HOME/.qclaw/skills"
  "$HOME/.workbuddy/skills"
)
```

### Find which agents have a skill installed

```bash
# Usage: find_skill_agents "my-skill" "$HOME/.agents/skills/my-skill"
find_skill_agents() {
  local SKILL_NAME="$1"
  local CANONICAL="$2"
  for DIR in "${ALL_AGENT_SKILLS[@]}"; do
    local LINK="$DIR/$SKILL_NAME"
    if [ -L "$LINK" ]; then
      local RESOLVED=$(python3 -c "import os; print(os.path.realpath('$LINK'))")
      if [ "$RESOLVED" = "$CANONICAL" ]; then
        echo "$DIR"
      fi
    fi
  done
}
```

### Create symlinks for multiple agents

```bash
# Usage: create_symlinks "my-skill" "$HOME/.agents/skills/my-skill" "${TARGET_DIRS[@]}"
create_symlinks() {
  local SKILL_NAME="$1"
  local CANONICAL="$2"
  shift 2
  local TARGET_DIRS=("$@")
  for DIR in "${TARGET_DIRS[@]}"; do
    mkdir -p "$DIR"
    if [ ! -L "$DIR/$SKILL_NAME" ]; then
      ln -s "$CANONICAL" "$DIR/$SKILL_NAME"
      echo "  Symlink: $DIR/$SKILL_NAME"
    fi
  done
}
```

### Remove symlinks from multiple agents

```bash
# Usage: remove_symlinks "my-skill" "$HOME/.agents/skills/my-skill"
remove_symlinks() {
  local SKILL_NAME="$1"
  local CANONICAL="$2"
  for DIR in "${ALL_AGENT_SKILLS[@]}"; do
    local LINK="$DIR/$SKILL_NAME"
    if [ -L "$LINK" ]; then
      local RESOLVED=$(python3 -c "import os; print(os.path.realpath('$LINK'))")
      if [ "$RESOLVED" = "$CANONICAL" ]; then
        rm "$LINK"
        echo "  Removed: $LINK"
      fi
    fi
  done
}
```

## Operations

### 1. Install a Skill from GitHub

**Steps:**
1. Clone the repository to a temporary directory
2. Locate the SKILL.md file and the skill directory
3. Detect installed agents (or use user-specified targets)
4. Copy the skill directory to `~/.agents/skills//`
5. Create symlinks for target agents
6. Update the lock file

```bash
# === Configuration ===
SKILL_NAME="my-skill"
REPO_SOURCE="owner/repo"
REPO_URL="https://github.com/owner/repo.git"
SKILL_FOLDER_PATH="skills/$SKILL_NAME"  # path to skill directory within repo

# === 1. Clone repo ===
TMPDIR=$(mktemp -d)
git clone --depth 1 "$REPO_URL" "$TMPDIR/repo"

# === 2. Locate skill directory ===
# Two path concepts (matching SkillManager's convention):
#   SKILL_FOLDER_PATH — directory containing SKILL.md (for git tree hash)
#   SKILL_FILE_PATH   — path to SKILL.md itself (for lock file's skillPath)
# Examples:
#   Sub-directory: folder="skills/foo", file="skills/foo/SKILL.md"
#   Root-level:    folder="",            file="SKILL.md"
SOURCE_DIR="$TMPDIR/repo/$SKILL_FOLDER_PATH"
if [ ! -f "$SOURCE_DIR/SKILL.md" ]; then
  # Fallback: search for SKILL.md
  FOUND=$(find "$TMPDIR/repo" -name "SKILL.md" -maxdepth 3 | head -1)
  if [ -n "$FOUND" ]; then
    SOURCE_DIR=$(dirname "$FOUND")
    # Derive folder path as relative path from repo root (empty string for root-level)
    SKILL_FOLDER_PATH="${SOURCE_DIR#$TMPDIR/repo/}"
    # Remove trailing slash if present (root case: "$TMPDIR/repo/" → "")
    SKILL_FOLDER_PATH="${SKILL_FOLDER_PATH%/}"
  else
    echo "❌ SKILL.md not found in repository"
    rm -rf "$TMPDIR"
    exit 1
  fi
fi

# Derive SKILL_FILE_PATH for lock entry: folder path + "/SKILL.md", or just "SKILL.md" at root
if [ -z "$SKILL_FOLDER_PATH" ]; then
  SKILL_FILE_PATH="SKILL.md"
else
  SKILL_FILE_PATH="$SKILL_FOLDER_PATH/SKILL.md"
fi

# === 3. Check not already installed ===
CANONICAL="$HOME/.agents/skills/$SKILL_NAME"
if [ -d "$CANONICAL" ]; then
  echo "❌ Skill '$SKILL_NAME' already exists. Use update instead."
  rm -rf "$TMPDIR"
  exit 1
fi

# === 4. Detect target agents (auto-detect all installed) ===
declare -A AGENT_DIRS=(
  ["claude"]="$HOME/.claude/skills"
  ["codex"]="$HOME/.codex/skills"
  ["gemini"]="$HOME/.gemini/skills"
  ["opencode"]="$HOME/.config/opencode/skills"
  ["antigravity"]="$HOME/.gemini/antigravity/skills"
  ["cursor"]="$HOME/.cursor/skills"
  ["kiro"]="$HOME/.kiro/skills"
  ["codebuddy"]="$HOME/.codebuddy/skills"
  ["openclaw"]="$HOME/.openclaw/skills"
  ["trae"]="$HOME/.trae/skills"
  ["qoder"]="$HOME/.qoder/skills"
  ["qclaw"]="$HOME/.qclaw/skills"
  ["workbuddy"]="$HOME/.workbuddy/skills"
)

TARGET_DIRS=()
for CMD in "${!AGENT_DIRS[@]}"; do
  if which "$CMD" &>/dev/null; then
    TARGET_DIRS+=("${AGENT_DIRS[$CMD]}")
  fi
done

# Copilot CLI is a gh extension, not a standalone binary — check explicitly
if which gh &>/dev/null && gh extension list 2>/dev/null | grep -q copilot; then
  TARGET_DIRS+=("$HOME/.copilot/skills")
fi

echo "Installing for ${#TARGET_DIRS[@]} agents: ${TARGET_DIRS[*]}"

# === 5. Copy to canonical directory ===
mkdir -p "$HOME/.agents/skills"
cp -R "$SOURCE_DIR" "$CANONICAL"

# === 6. Create symlinks ===
for DIR in "${TARGET_DIRS[@]}"; do
  mkdir -p "$DIR"
  ln -s "$CANONICAL" "$DIR/$SKILL_NAME"
  echo "  Symlink: $DIR/$SKILL_NAME"
done

# === 7. Update lock file ===
cd "$TMPDIR/repo"
# SKILL_FOLDER_PATH is empty for root-level skills; git rev-parse HEAD: returns root tree hash
TREE_HASH=$(git rev-parse HEAD:$SKILL_FOLDER_PATH 2>/dev/null || echo "")
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

# Export variables so python3 can read them via os.environ
export SKILL_NAME REPO_SOURCE REPO_URL SKILL_FILE_PATH TREE_HASH NOW
python3 /dev/null || echo "")
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

export SKILL_NAME SKILL_FILE_PATH TREE_HASH NOW
python3 /dev/null)
  echo "  - $NAME: $DESC"
done
```

### 5. Assign / Unassign Skill to Agent

```bash
SKILL_NAME="my-skill"
AGENT_SKILLS_DIR="$HOME/.claude/skills"  # change to target agent
CANONICAL="$HOME/.agents/skills/$SKILL_NAME"

# Assign
mkdir -p "$AGENT_SKILLS_DIR"
[ -L "$AGENT_SKILLS_DIR/$SKILL_NAME" ] || ln -s "$CANONICAL" "$AGENT_SKILLS_DIR/$SKILL_NAME"

# Unassign
[ -L "$AGENT_SKILLS_DIR/$SKILL_NAME" ] && rm "$AGENT_SKILLS_DIR/$SKILL_NAME"
```

### 6. Search for Skills

```bash
# skills.sh registry
curl -s "https://skills.sh/api/search?q=your-query" | python3 -m json.tool

# ClawHub
curl -s "https://api.clawhub.com/v1/skills/search?q=your-query" | python3 -m json.tool
```

## Important Notes

1. **SkillDeck auto-refreshes**: The GUI watches `~/.agents/skills/` and all agent directories. Changes via shell are reflected in the GUI within 0.5s.

2. **Lock file compatibility**: Format is v3 (shared with `npx skills`). Always preserve `version: 3` and existing entries.

3. **Cross-directory inheritance**: Symlinks in `~/.claude/skills/` are also visible to Copilot, OpenCode, and Cursor. Don't create redundant symlinks.

4. **Codex special case**: Reads `~/.agents/skills/` natively. Symlink in `~/.codex/skills/` is optional but consistent.

5. **Never modify**: `~/.agents/.skilldeck-cache.json` (SkillDeck private cache)

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [crossoverJie](https://github.com/crossoverJie)
- **Source:** [crossoverJie/SkillDeck](https://github.com/crossoverJie/SkillDeck)
- **License:** MIT
- **Homepage:** http://crossoverjie.top/SkillDeck/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** yes
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-crossoverjie-skilldeck-skilldeck
- Seller: https://agentstack.voostack.com/s/crossoverjie
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
