Skip to content

mdm skills add

Install a skill from GitHub, GitLab, a URL, or a local path.

Usage

mdm skills add <package>

<package> can be any of:

Format Example
GitHub shorthand owner/repo
Full GitHub URL https://github.com/owner/repo
GitLab URL https://gitlab.com/owner/repo
Git URL with ref https://github.com/owner/repo#main
Local path ./my-local-skill
Well-known alias vercel, anthropic

Install flow

  1. The source is fetched (shallow clone or GitHub API tree query).
  2. SKILL.md files inside the repo are discovered.
  3. If the repo contains multiple skills, a picker lets you choose which ones to install.
  4. You are prompted for scope (project or global) and which harnesses to install to - unless flags are provided.
  5. Markdown files are scanned for hidden Unicode characters.
  6. One canonical copy of each skill is written to .agents/skills/<name>, and each harness with a skills directory of its own is symlinked to it (or given a real copy, in copy mode).
  7. The installation is recorded in mdm.lock.

Installing from a directory that is already the destination

mdm skills add . walks the whole project for SKILL.md files, so it finds mdm's own canonical copies under .agents/skills as well as your sources. When a skill's source directory turns out to be its install destination, mdm skips the copy rather than performing it.

The skip is not an error. Asking to install something that is already exactly in place is a reasonable thing to do, and there is nothing for you to fix. In the default symlink mode the skip covers the copy only - the harness symlink is still created, so mdm skills add . --harness roo on an already-installed skill still does the one useful thing it can.

Sameness is decided by inspecting the files, not by comparing path strings, so the common shape of this is caught too: a harness's .claude/skills/<name> symlink discovered as the source while the destination is the .agents/skills/<name> it points at. Two spellings, one directory.

Flags

Flag Description
--global, -g Install globally (user-level, ~/.agents/skills/)
--project, -p Force project-scope install
--harness Harnesses to install to (repeatable; use * for all)
--skill, -s Skill names to install (repeatable; use * for all)
--list, -l List available skills without installing
--yes, -y Skip all confirmation prompts
--copy Copy files instead of symlinking; switches the scope to copy mode
--symlink Symlink files from .agents/skills (the default); switches a scope back from copy mode
--all Install every skill to every harness without prompting (shorthand for --skill '*' --harness '*' -y)
--full-depth Search all subdirectories for SKILL.md files
--skip-audit Skip the security audit check
--fail-on-audit Exit non-zero when security findings are detected instead of prompting (CI-friendly)
--allow-hidden-chars Allow markdown files with hidden Unicode characters

The --harness and --skill flags accept multiple space-separated values after a single flag or can be repeated:

mdm skills add owner/repo --harness claude-code cursor
mdm skills add owner/repo --harness claude-code --harness cursor   # equivalent

Harness selection

The harness picker shows harnesses with unique skills directories in the left panel. Harnesses that are always auto-covered (shared .agents/skills directory) appear in a locked panel to the right - they are always installed to and cannot be deselected.

Which harnesses would you like to install to?  │  always included:
  > filter...                                  │  ◉ Codex
  ❯ ● Claude Code                             │  ◉ Gemini CLI
    ○ Cursor                                  │  ◉ Warp
    ○ Windsurf                                │  ...
  type to filter · space to toggle · enter to confirm

If you have a configured harness list (set via mdm harnesses add or mdm rules link), those harnesses are pre-checked. Otherwise harnesses detected as installed are pre-checked. Your selection is saved back to configuredHarnesses for future installs.

Harnesses that use the shared .agents/skills directory but also have a unique instruction file (such as GitHub Copilot, which uses .github/copilot-instructions.md) do not appear in the left panel - they are always included via the locked panel. If such a harness was previously configured via mdm rules link, it is preserved in configuredHarnesses even though it is not shown as a selectable option.

Project scope (default): skills are installed under .agents/skills/ in the current directory. Each harness that has its own skills directory gets a symlink pointing to the shared location.

Global scope (-g): skills are installed under ~/.agents/skills/. Harnesses with a global skills directory get a symlink to that shared location.

Copy mode (--copy): instead of symlinking from harness directories to .agents/skills/, files are copied directly. Use this if your tools don't follow symlinks.

When a symlink cannot be created (Windows without Developer Mode or the symlink privilege, typically), the install is copied instead and nothing is recorded: the scope stays in symlink mode, and a warning after the install summary names the harnesses that got copies. If copies are what you want on that machine, run with --copy once to record it.

The install mode is a scope-wide switch, not a per-skill one. Passing --copy records installMode: copy in the scope's lock, so later installs, updates, and restores in that scope copy without repeating the flag. Passing --symlink switches the scope back: it records symlink mode and turns the copied installs back into links, so there is no need to edit the lock by hand. Symlink is the default, so --symlink on a scope that has never been switched changes nothing. The two flags cannot be combined. Switching a scope that already has installs re-materializes them into the new mode instead of leaving a mix, and reports how many it converted; the flag itself is the consent, so there is no extra confirmation. The switch is applied only once everything that could still stop the install has passed: the harness selection and the security-audit confirmation. Backing out at either of them leaves the install mode and the skills untouched, though an interactive harness picker already saves your selection to configuredHarnesses before the audit gate, so that part of the record can persist even when you decline it.

The conversion covers every harness directory the scope supports, not just the harnesses recorded in configuredHarnesses. That list holds only what you last picked in the interactive harness picker, so a harness you installed to with --harness <harness> -y is converted along with the rest rather than being left behind on symlinks.

Only what mdm installed is converted. Switching to copy mode converts the symlinks pointing into the scope's .agents/skills directory; a symlink you put in a harness's skills directory yourself, pointing somewhere else, is left exactly as it is. The .agents/skills copy each converted link pointed at also stays: harnesses that read that shared directory install into it in copy mode too, so it keeps being refreshed. Switching back to symlink mode converts the real directories that hold a SKILL.md, creating the .agents/skills copy first when a copy install never wrote one; a directory without a SKILL.md is not an mdm install and is left alone.

Examples

# Install interactively - prompts for scope, harnesses, and skill selection
mdm skills add vercel-labs/agent-skills

# Install a specific skill, skip prompts
mdm skills add vercel-labs/agent-skills --skill vercel-react-best-practices -y

# Install all skills globally to all harnesses
mdm skills add anthropics/skills --all -g

# Install from a specific branch
mdm skills add owner/repo#feat/my-branch

# Install from a local directory
mdm skills add ./my-skill

# List skills in a package without installing
mdm skills add vercel-labs/agent-skills --list

# Install to specific harnesses only
mdm skills add owner/repo --harness claude-code cursor

Installing vs forking

add keeps a skill in sync with its author: mdm skills update re-fetches it from the recorded source and ref, replacing whatever is on disk. That makes it the wrong command for a skill you intend to change - your edits are gone at the next update.

To take a third-party skill and build on it, use mdm skills cherry-pick instead. It copies the skill into ./skills as part of your own repository, records where it came from and under what license, and is deliberately left alone by mdm skills update.

Security audit

When installing public skills from GitHub, mdm checks the skills.sh registry for any known security advisories. If an advisory is found you are shown the details and asked to confirm before proceeding. Pass --skip-audit to disable this check.

Hidden character scan

Before installing, mdm scans all markdown files in the selected skill for hidden Unicode characters used in prompt-smuggling attacks, including Unicode tags, bidirectional controls, zero-width characters, variation selectors, and soft hyphens. Blocking findings stop the installation even with --yes. Pass --allow-hidden-chars to continue intentionally.

Variation selectors that complete a valid emoji sequence, such as the U+FE0F in ⚠️, are reported as warnings and do not block. See Hidden-character scan for the full tiering.