# Skills

This section covers adding custom skills to OpenClaw on Cloudeka, including both simple single-file skills and complex nested folder structures.

## What are Skills?

Skills extend OpenClaw's capabilities with specialized tools and knowledge. A skill can:

* Define new tools via MCP (Model Context Protocol) servers
* Add specialized knowledge and instructions
* Provide helper scripts and utilities

Skills are stored in an agent's `workspace/skills/` directory.

## Skill Structure

### Minimal Skill (Single File)

```
my-skill/
└── SKILL.md
```

### Complex Skill (Nested)

```
my-skill/
├── SKILL.md
├── lib/
│   └── helpers.ts
├── templates/
│   └── prompt.md
└── config.json
```

{% hint style="warning" %}
Kubernetes ConfigMaps are flat — they don't support nested directories. We'll handle this differently based on skill complexity.
{% endhint %}

## Method 1: Single-File Skills (Simple)

For skills with only a `SKILL.md` file, use a direct ConfigMap mount.

### Step 1: Create the Skill File

Create `my-skill/SKILL.md`:

```markdown
---
name: my-skill
description: A brief description of what this skill does
metadata: {"openclaw":{"requires":{"bins":[]}}}
---

# My Skill

Describe what the skill does and how to use it.

## Usage

Example usage here.
```

### Step 2: Create ConfigMap

```bash
kubectl create configmap my-skill \
  --from-file=SKILL.md=./my-skill/SKILL.md \
  -n openclaw
```

### Step 3: Add to values.yaml

```yaml
# charts/openclaw/values.yaml
app-template:
  persistence:
    my-skill:
      enabled: true
      type: configMap
      name: my-skill
      advancedMounts:
        main:
          main:
            - path: /home/node/.openclaw/workspace/skills/my-skill/SKILL.md
              subPath: SKILL.md
              readOnly: true
```

### Step 4: Upgrade Helm Release

```bash
helm upgrade openclaw ./charts/openclaw -n openclaw -f charts/openclaw/values.yaml
```

## Method 2: Folder-Based Skills (Tar Archive)

For skills with nested directories, use a tar archive approach.

### Step 1: Prepare Your Skill Folder

```
my-advanced-skill/
├── SKILL.md
├── lib/
│   └── utils.ts
├── templates/
│   └── prompt.md
└── config.json
```

### Step 2: Create Tar Archive

```bash
# Create tar.gz from the skill folder
tar czf /tmp/my-advanced-skill.tar.gz -C ./skills-folder my-advanced-skill

# Verify contents
tar tzf /tmp/my-advanced-skill.tar.gz
# Expected output:
# my-advanced-skill/
# my-advanced-skill/SKILL.md
# my-advanced-skill/lib/utils.ts
# my-advanced-skill/templates/prompt.md
# my-advanced-skill/config.json
```

### Step 3: Create ConfigMap from Tar

```bash
kubectl create configmap my-advanced-skill-skill \
  --from-file=skill.tar.gz=/tmp/my-advanced-skill.tar.gz \
  -n openclaw
```

### Step 4: Add to values.yaml

Mount to `init-skills` container for extraction:

```yaml
# charts/openclaw/values.yaml
app-template:
  persistence:
    my-advanced-skill-skill:
      enabled: true
      type: configMap
      name: my-advanced-skill-skill
      advancedMounts:
        main:
          init-skills:
            - path: /tmp/skills/my-advanced-skill
              readOnly: true
```

### Step 5: Update init-skills Command

Add extraction logic to `init-skills` command in values.yaml:

```yaml
# charts/openclaw/values.yaml
app-template:
  controllers:
    main:
      initContainers:
        init-skills:
          command:
            - sh
            - -c
            - |
              log() { echo "[$(date -Iseconds)] [init-skills] $*"; }

              log "Starting skills initialization"

              # ============================================================
              # Runtime Dependencies
              # ============================================================
              mkdir -p /home/node/.openclaw/bin
              if [ ! -f /home/node/.openclaw/bin/uv ]; then
                log "Installing uv..."
                curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/home/node/.openclaw/bin sh
              fi

              mkdir -p /home/node/.openclaw/node_modules/.bin
              if [ ! -f /home/node/.openclaw/node_modules/.bin/mcporter ]; then
                log "Installing mcporter..."
                cd /home/node/.openclaw && npm install mcporter
              fi

              # ============================================================
              # Extract Skill Archives
              # ============================================================
              # Extract tar.gz skill archives to workspace
              for archive in /tmp/skills/*/skill.tar.gz; do
                if [ -f "$archive" ]; then
                  log "Extracting skill archive: $archive"
                  tar xzf "$archive" -C /home/node/.openclaw/workspace/skills/
                fi
              done

              # ============================================================
              # Install ClawHub Skills
              # ============================================================
              mkdir -p /home/node/.openclaw/workspace/skills
              cd /home/node/.openclaw/workspace
              for skill in weather; do
                if [ -n "$skill" ] && [ ! -d "skills/${skill##*/}" ]; then
                  log "Installing skill: $skill"
                  if ! npx -y clawhub install "$skill" --no-input; then
                    log "WARNING: Failed to install skill: $skill"
                  fi
                else
                  log "Skill already installed: $skill"
                fi
              done

              log "Skills initialization complete"
```

### Step 6: Upgrade Helm Release

```bash
helm upgrade openclaw ./charts/openclaw -n openclaw -f charts/openclaw/values.yaml
```

## Updating Skills

### Single-File Skills

Update the ConfigMap and restart:

```bash
# Delete and recreate
kubectl delete configmap my-skill -n openclaw
kubectl create configmap my-skill \
  --from-file=SKILL.md=./my-skill/SKILL.md \
  -n openclaw

# Restart pod
kubectl rollout restart deployment openclaw -n openclaw
```

### Folder-Based Skills

Same process — recreate ConfigMap and restart:

```bash
# Recreate tar
tar czf /tmp/my-advanced-skill.tar.gz -C ./skills-folder my-advanced-skill

# Update ConfigMap
kubectl delete configmap my-advanced-skill-skill -n openclaw
kubectl create configmap my-advanced-skill-skill \
  --from-file=skill.tar.gz=/tmp/my-advanced-skill.tar.gz \
  -n openclaw

# Restart pod
kubectl rollout restart deployment openclaw -n openclaw
```

## Per-Agent Skills

In a multi-agent setup, each agent can have its own set of skills:

```yaml
# Skill for "main" agent
main-weather-skill:
  enabled: true
  type: configMap
  name: weather-skill
  advancedMounts:
    main:
      main:
        - path: /home/node/.openclaw/workspace-main/skills/weather/SKILL.md
          subPath: SKILL.md
          readOnly: true

# Skill for "docs" agent only
docs-wiki-skill:
  enabled: true
  type: configMap
  name: docs-wiki-skill
  advancedMounts:
    main:
      main:
        - path: /home/node/.openclaw/workspace-docs/skills/wiki/SKILL.md
          subPath: SKILL.md
          readOnly: true
```

See [Multi-Agent](/guidance-for-individual/reference/how-to-deployment-openclaw-on-cloudeka/multi-agent.md) Guide for complete multi-agent setup.

## MCP Server Integration

Skills can integrate MCP servers for external tools:

### Example: Database Query Skill

1. **Create** `SKILL.md`:

````markdown
---
name: my-db-skill
description: Query incident database
metadata: {"openclaw":{"requires":{"bins":["mcporter"]},"primaryEnv":"DB_URL"}}
---

# Database Query Skill

You have access to the incident database via `mcporter`.

## Available Tools

### query_tickets
Query tickets by filters.

```bash
mcporter call my-db.query_tickets status:open priority:critical
````

2. **Create MCP config:**

````
```json
{
  "mcpServers": {
    "my-db": {
      "description": "Incident database",
      "baseUrl": "http://mcp-server:3000/mcp"
    }
  }
}
````

3. **Create ConfigMap for MCP config**:

```bash
kubectl create configmap my-db-mcporter-config \
  --from-file=mcporter.json=./mcporter.json \
  -n openclaw
```

4. **Mount to agent workspace**:

```yaml
my-db-mcporter-config:
  enabled: true
  type: configMap
  name: my-db-mcporter-config
  advancedMounts:
    main:
      main:
        - path: /home/node/.openclaw/workspace/config/mcporter.json
          subPath: mcporter.json
          readOnly: true
```

5. **Add environment variable**:

```bash
kubectl patch secret openclaw-env-secret -n openclaw \
  --type='merge' \
  -p='{"stringData":{"DB_URL": "postgresql://user:pass@host:5432/db"}}'
```

## Skill Best Practices

1. **Keep skills focused** — One skill should do one thing well
2. **Use metadata** — Declare dependencies and environment variables
3. **Document tools** — Provide clear examples for each tool
4. **Version control** — Store skill definitions in git
5. **Test locally** — Validate skill behavior before deploying

## Common Issues

<table><thead><tr><th width="222.4444580078125">Issue</th><th>Solution</th></tr></thead><tbody><tr><td>Skill not found</td><td>Check mount path matches workspace</td></tr><tr><td>Nested files missing</td><td>Use tar archive method</td></tr><tr><td>Permission denied</td><td>Ensure PVC is writable (init-skills has access)</td></tr><tr><td>MCP server unreachable</td><td>Verify baseUrl and network policy</td></tr></tbody></table>

## Example Skills Repository

Structure for managing multiple skills:

```
openclaw-skills/
├── skills/
│   ├── weather/
│   │   └── SKILL.md
│   ├── aira-db/
│   │   ├── SKILL.md
│   │   ├── lib/
│   │   │   └── db.ts
│   │   └── templates/
│   │       └── query.md
│   └── kubectl/
│       └── SKILL.md
├── deploy.sh
└── README.md
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.cloudeka.ai/guidance-for-individual/reference/how-to-deployment-openclaw-on-cloudeka/skills.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
