> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runlayer.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Skills

> Author, publish, and install reusable prompt packages with the Runlayer CLI.

## Overview

Skills are reusable prompt packages that live as directories — each containing a `SKILL.md` file with frontmatter and supporting files. Publish a skill once and your team can install the same vetted, version-controlled instructions into Claude Code, Cursor, and other clients. There are two workflows:

* **Author & publish** — write skills in your repo, push them to Runlayer with `skills push` (typically in CI)
* **Consume & install** — add published skills to your project or global config with `skills add`

***

## Authoring skills

### Directory structure

```
skills/
  ticket-triage/
    SKILL.md          # required — must have `name` in frontmatter
    instructions.md
    examples.txt
  code-review/
    SKILL.md
    checklist.md
```

### SKILL.md frontmatter

```yaml theme={null}
---
name: Ticket Triage
description: Classify and route incoming support tickets
---

Your skill instructions go here...
```

| Field         | Required | Notes                                |
| ------------- | -------- | ------------------------------------ |
| `name`        | Yes      | Human-readable label shown in the UI |
| `description` | No       | Short summary, max 1024 characters   |

The directory path (e.g. `skills/ticket-triage`) is the stable sync key. Renaming the directory creates a new skill; changing `name` in frontmatter updates the display name.

Supported UTF-8 text file types: `.css`, `.csv`, `.html`, `.js`, `.json`, `.md`, `.markdown`, `.py`, `.sh`, `.svg`, `.ts`, `.txt`, `.xml`, `.yaml`, `.yml`. CSV files have table previews; isolated HTML/SVG previews require a low-risk security scan. Binary files such as PNGs and PDFs are not supported.

***

## Publishing

Push skills from a local directory to the Runlayer API.

```bash theme={null}
uvx runlayer skills push [PATH] --namespace <namespace> [OPTIONS]
```

| Flag              | Description                                                                             |
| ----------------- | --------------------------------------------------------------------------------------- |
| `--namespace, -N` | Required. Groups skills by repo (e.g. `myorg/my-repo`)                                  |
| `--public`        | Publish pushed skills as public                                                         |
| `--host, -H`      | Runlayer host URL. Also reads `RUNLAYER_HOST` env var                                   |
| `--secret, -s`    | API key override (optional; prefer `uvx runlayer login`). Also reads `RUNLAYER_API_KEY` |
| `--dry-run, -n`   | Show what would change without making API calls                                         |
| `--prune`         | Delete remote skills whose directories no longer exist locally                          |
| `PATH`            | Root directory to scan. Defaults to `.`                                                 |

### Examples

```bash theme={null}
# Preview changes
uvx runlayer skills push --namespace myorg/repo -n

# Push skills
uvx runlayer skills push --namespace myorg/repo

# Push skills and make them public
uvx runlayer skills push --namespace myorg/repo --public

# Push and remove deleted skills
uvx runlayer skills push --namespace myorg/repo --prune

# Delete all skills in a namespace (run from empty dir)
cd $(mktemp -d) && uvx runlayer skills push --namespace myorg/repo --prune
```

### How push works

1. CLI walks the directory tree looking for `SKILL.md` files
2. Each `SKILL.md` must have `name` in its YAML frontmatter (directories without it are skipped)
3. The directory path relative to root becomes the skill's `path` — this is the stable key used to match local and remote skills
4. For each discovered skill:
   * **New path** — creates the skill and uploads all files
   * **Existing path** — compares name, description, and file contents; updates only what changed
   * **Remote-only path** (with `--prune`) — deletes the skill from Runlayer

### GitHub Actions

```yaml theme={null}
name: Push Skills
on:
  push:
    branches: [main]
    paths:
      - 'skills/**'

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: astral-sh/setup-uv@v4

      - run: uvx runlayer skills push --namespace ${{ github.repository }} --prune
        env:
          RUNLAYER_HOST: ${{ secrets.RUNLAYER_HOST }}
          RUNLAYER_API_KEY: ${{ secrets.RUNLAYER_API_KEY }}
```

Set `RUNLAYER_HOST` and `RUNLAYER_API_KEY` as repository secrets.

The `paths` filter ensures the workflow only runs when files under `skills/` change. The `--prune` flag removes skills from Runlayer when their directory is deleted from the repo.

***

## Creating from the web UI

From the **Skills** page, click **Add skill**. You can:

* **Import from GitHub** — paste a public GitHub repo URL (e.g. `github.com/owner/repo` or `github.com/owner/repo/tree/branch/path`). Runlayer discovers skill directories (each with a `SKILL.md`) and lets you choose which to import. Imported skills are linked to their source URL and can be re-synced when the upstream changes.
* **Upload files** — drag a `.zip`/`.skill` archive (must contain a `SKILL.md` at the top or inside a single root folder), a single `.md`/`.markdown` file (treated as `SKILL.md`), or a folder.
* **Use a template** — start from a pre-built skill template.

After upload or import, Runlayer parses the frontmatter, runs a security scan, and shows the results before the skill is created.

***

## Using skills in AI clients

Open a skill and click **Add to Client**. If the skill is included in [Runlayer Plugin](/runlayer-plugin), Runlayer recommends that shared connection first. Click **Connect** to use Runlayer Plugin, or continue with the client-specific instructions to install the skill directly.

To work with several skills at once:

1. Open **Skills** and select the skill cards.
2. Click **Add to Client** in the selection bar.
3. Use Runlayer Plugin, add the skills to an editable Plugin, or create a new Plugin.

See [Plugins](/platform-plugins#creating-or-extending-a-plugin) for the complete flow.

***

## Security scanning

When you upload or update skill files — via the CLI (`skills push`), web import from GitHub, the API, or the web UI — Runlayer automatically scans each file with ToolGuard. The scan runs before the file is accepted, and the results (per-file risk scores and an overall skill classification) are shown in the skill detail page.

After upload, the skill detail page displays the overall security score and per-file risk indicators. Click the score badge to open a dialog showing per-file findings — grouped by concern level — so you can review exactly which lines triggered each score.

If a skill was created before security scanning was enabled, or if you want to re-evaluate after updating files, skill owners and admins can trigger a manual rescan from the skill detail page using the **Scan security** button.

The platform enforces a configurable **skill risk policy** based on the scan result. By default, high-risk skills are blocked and medium-risk skills show a warning. Admins can adjust these actions in **Settings → Security Scanners**. See [ToolGuard Models — Skill Risk Policy](/runlayer-toolguard#skill-risk-policy) for details.

### Why a skill gets blocked

The scan combines ToolGuard's ML threat classification with additional deterministic checks. Each finding appears in the findings dialog with a severity, the matched content, and a line reference, and is tagged with a risk category from the [ToolGuard threat taxonomy](/runlayer-toolguard#llm-risk-categorization) (for example Data Exfiltration, Privilege Escalation, Context Poisoning, Destructive Action, or Guardrail Bypass) — so reviewers see what was flagged and why, not just a score.

Per-file results map to the same [risk tiers](/runlayer-toolguard#risk-tiers) used across ToolGuard. A serious finding raises the file to High risk — rejected by the default policy — while lower-severity findings surface as a Medium-risk warning and import with a warning by default. Typical High-risk triggers include hidden-character obfuscation, piping downloads into a shell, and referencing credential material; typical warnings include network access, destructive commands, dynamic code execution, and encoded payloads.

When an admin accepts a medium-risk warning, the acceptance is recorded in the [Audit Log](/platform-audit-logs).

### Scanning from the CLI

You can also scan one skill, or a folder containing many skills, on-demand before publishing:

```bash theme={null}
uvx runlayer skills scan <path-to-skill-dir-or-SKILL.md>
```

| Flag           | Description                                                                   |
| -------------- | ----------------------------------------------------------------------------- |
| `--name`       | Override skill name sent to the security scan API for single-skill scans only |
| `--fail-on`    | Exit non-zero on `warn` or `block` result (useful in CI)                      |
| `--secret, -s` | API key override. Also reads `RUNLAYER_API_KEY`                               |
| `--host, -H`   | Runlayer host URL. Also reads `RUNLAYER_HOST`                                 |

This calls the same ToolGuard security scan API used by `skills push`, but without uploading. Single-skill scans return one scan object; multi-skill scans return a JSON object with a `skills` array. Use `--fail-on block` in CI pipelines to gate merges on security scan results.

#### CI gate example

Run the scan as a required check on pull requests so a risky skill never reaches `main`:

```yaml theme={null}
name: Scan Skills
on:
  pull_request:
    paths:
      - 'skills/**'

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: astral-sh/setup-uv@v4

      - run: uvx runlayer skills scan skills/ --fail-on block
        env:
          RUNLAYER_HOST: ${{ secrets.RUNLAYER_HOST }}
          RUNLAYER_API_KEY: ${{ secrets.RUNLAYER_API_KEY }}
```

`--fail-on block` exits non-zero when any skill classifies as block-level risk, failing the check; use `--fail-on warn` to also fail on medium-risk warnings. The scan only evaluates files — it does not upload or publish — so pair it with the [push workflow](#github-actions) above (scan on `pull_request`, publish on `push` to `main`).

***

## Installing

Add published skills from the Runlayer API to your local project or global config.

```bash theme={null}
uvx runlayer skills add [SOURCE] [OPTIONS]
```

| Flag            | Description                                                                             |
| --------------- | --------------------------------------------------------------------------------------- |
| `source`        | Optional when `--all` is used. Skill UUID or namespace (e.g. `Org/Repo`)                |
| `--all`         | Install all accessible skills across namespaces                                         |
| `--skill`       | Filter by skill name within a namespace                                                 |
| `--client, -c`  | Target editor client: `claude_code` (default), `cursor`, `goose`, `opencode`, `vscode`  |
| `--global, -g`  | Install globally instead of project-level                                               |
| `--dry-run, -n` | Show what would be installed without writing files                                      |
| `--secret, -s`  | API key override (optional; prefer `uvx runlayer login`). Also reads `RUNLAYER_API_KEY` |
| `--host, -H`    | Runlayer host URL. Also reads `RUNLAYER_HOST` env var                                   |

### Examples

```bash theme={null}
# Install all skills from a namespace
uvx runlayer skills add myorg/my-repo

# Install all accessible skills across namespaces
uvx runlayer skills add --all

# Install a single skill by name
uvx runlayer skills add myorg/my-repo --skill ticket-triage

# Install globally
uvx runlayer skills add myorg/my-repo --global

# Install for Cursor instead of Claude Code
uvx runlayer skills add myorg/my-repo --client cursor
```

If `--all` sees the same skill name in multiple namespaces, install fails with an explicit error. Re-run with a namespace `SOURCE` (or UUID) to disambiguate.

Typical output:

```text theme={null}
Done: 12 installed, 3 skipped
```

Validation errors:

```text theme={null}
Pass either SOURCE or --all, not both.
Missing argument 'SOURCE'. Use SOURCE or --all.
```

### File layout

Skills are written to a canonical directory and, for some clients, an editor-specific directory via symlink:

| Scope   | Canonical           | Claude Code         | Codex              | Cursor              | Goose / VS Code / OpenCode   |
| ------- | ------------------- | ------------------- | ------------------ | ------------------- | ---------------------------- |
| Project | `.agents/skills/`   | `.claude/skills/`   | `.codex/skills/`   | `.cursor/skills/`   | `.agents/skills/` (direct)   |
| Global  | `~/.agents/skills/` | `~/.claude/skills/` | `~/.codex/skills/` | `~/.cursor/skills/` | `~/.agents/skills/` (direct) |

Goose, VS Code, and OpenCode read from the canonical directory directly — no symlinks are created for these clients.

A lockfile at `.runlayer/skill-lock.yml` (or `~/.runlayer/skill-lock.yml` for global) tracks installed skills and versions per client.

#### Symlink behavior

* Skill files are stored in the canonical directory (`.agents/skills/` or `~/.agents/skills/`).
* Claude Code, Codex, and Cursor directories contain symlinks to the canonical location. Goose, VS Code, and OpenCode use the canonical directory directly.

Example (project install for Claude Code):

```text theme={null}
.agents/skills/ticket-triage/          # real files
.claude/skills/ticket-triage -> ../../.agents/skills/ticket-triage
```

Client-scoped lifecycle:

* `uvx runlayer skills remove --client <client>` removes only that client's symlink + lockfile entry.
* Canonical files are kept while any other client still references the same skill.
* Canonical files are deleted only when the last client reference is removed.

If symlink creation is blocked by filesystem policy or permissions, install fails for clients that require symlinks. Run in a writable path that supports symlinks.

***

## Interactive find

Browse and install skills interactively from the terminal.

```bash theme={null}
uvx runlayer skills find
```

The command loads all available skills, presents a searchable multi-select list, then prompts you to choose target clients and install scope (project or global). No flags are required — the wizard walks you through each step.

| Flag           | Description                                     |
| -------------- | ----------------------------------------------- |
| `--secret, -s` | API key override. Also reads `RUNLAYER_API_KEY` |
| `--host, -H`   | Runlayer host URL. Also reads `RUNLAYER_HOST`   |

***

## Managing installed skills

### List

```bash theme={null}
uvx runlayer skills list [OPTIONS]
```

| Flag           | Description                                                                            |
| -------------- | -------------------------------------------------------------------------------------- |
| `--client, -c` | Target editor client: `claude_code` (default), `cursor`, `goose`, `opencode`, `vscode` |
| `--global, -g` | List global skills                                                                     |

`list`, `update`, and `remove` are scoped to the selected `--client`.

### Update

Pull the latest versions of installed skills from the API.

```bash theme={null}
uvx runlayer skills update [OPTIONS]
```

| Flag            | Description                                                                             |
| --------------- | --------------------------------------------------------------------------------------- |
| `--skill`       | Update a specific skill only                                                            |
| `--client, -c`  | Target editor client (default: `claude_code`)                                           |
| `--global, -g`  | Update global skills                                                                    |
| `--dry-run, -n` | Show what would change without writing files                                            |
| `--secret, -s`  | API key override (optional; prefer `uvx runlayer login`). Also reads `RUNLAYER_API_KEY` |
| `--host, -H`    | Runlayer host URL. Also reads `RUNLAYER_HOST` env var                                   |

<Note>
  **Do installed skills auto-update?** No. Files written by `skills add` are pinned in the lockfile (`.runlayer/skill-lock.yml`) and do not change until you run `skills update` (or re-run `runlayer setup sync`, which your MDM can schedule). If you connect the org-wide [Runlayer Plugin](/runlayer-plugin) instead of installing files, the skills a user can access are resolved on each request, so published changes are reflected automatically with no reinstall.
</Note>

### Remove

```bash theme={null}
uvx runlayer skills remove [SKILL_NAME] [OPTIONS]
```

| Flag           | Description                                         |
| -------------- | --------------------------------------------------- |
| `name`         | Optional when `--all` is used. Skill name to remove |
| `--all`        | Remove all installed skills in the selected scope   |
| `--yes`        | Skip confirmation prompt for `--all`                |
| `--client, -c` | Target editor client (default: `claude_code`)       |
| `--global, -g` | Remove from global skills                           |

### Remove examples

```bash theme={null}
# Remove one skill
uvx runlayer skills remove ticket-triage

# Remove all project skills (prompts for confirmation)
uvx runlayer skills remove --all

# Remove all global skills without prompt
uvx runlayer skills remove --all --global --yes
```

Typical output (examples):

```text theme={null}
Remove 5 skill(s) from project install? [y/N]:
Aborted.
```

```text theme={null}
Done: 5 removed
```

***

## From repo to Claude and Cursor

How a skill authored in a repo ends up in a teammate's Claude Code or Cursor session, end to end:

1. **Author & publish** — write skills under `skills/` in your repo and push them with `uvx runlayer skills push --namespace <org/repo>`, typically from CI (see [GitHub Actions](#github-actions) above). Every upload is [security scanned](#security-scanning) before it is accepted.
2. **(Optional) Bundle into a plugin** — select skills on the **Skills** page and click **Add to Client**, create a Plugin from the **Plugins** page, or use `uvx runlayer plugins push`. See [Plugins](/platform-plugins#creating-or-extending-a-plugin).
3. **Install on dev machines** — each developer runs `skills add` or `plugins add`, which writes files into the client-specific directories (`.claude/skills/`, `.cursor/skills/`, etc. — see [File layout](#file-layout)) so the client picks them up.
4. **Or roll out org-wide** — admins enable **Auto Sync** on connectors or plugins in the dashboard; developers (or your MDM) run `uvx runlayer setup sync`, which auto-detects installed clients (Claude Desktop, Claude Code, Cursor, VS Code, and more) and writes the config. See [Auto-Sync to Clients](/auto-provisioning).
5. **Or use Runlayer Plugin** — instead of installing skills file-by-file, connect the org-wide [Runlayer Plugin](/runlayer-plugin) MCP entrypoint, which exposes every skill the user can access through search tools.

***

## Related Resources

<CardGroup cols={2}>
  <Card title="Plugins" icon="puzzle" href="/platform-plugins">
    Bundle skills and connectors into a single reusable toolset
  </Card>

  <Card title="Agents" icon="robot" href="/platform-agents">
    Attach skills to agents to extend what they can do
  </Card>

  <Card title="ToolGuard" icon="shield" href="/runlayer-toolguard">
    How skill files are scanned for security risks
  </Card>

  <Card title="Connectors" icon="plug" href="/platform-connectors">
    Add and manage MCP servers your skills can use
  </Card>
</CardGroup>
