Skip to content

Creating a Custom Skill

Paulo Maia Carvalho edited this page May 20, 2026 · 1 revision

Creating a Custom Skill

A skill is a single SKILL.md file that teaches the agent how to perform a task. The agent reads it, runs the bash blocks in order, and uses the markdown prose to make decisions between steps.

File structure

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

The folder name becomes the slash command: skills/drupal-cr//drupal-cr.

SKILL.md anatomy

---
name: my-skill
description: One-line description shown in the skills panel.
distribution: public
---

# my-skill

Brief explanation of what this skill does.

## Step 1 — Do something

```bash
echo "This runs as a bash script"
RESULT=$(some-command)
echo "RESULT=$RESULT"

Interpret the output. If RESULT is empty, tell the user and stop.

Step 2 — Do something else

echo "Step 2 bash"

### Frontmatter fields

| Field | Required | Description |
|---|---|---|
| `name` | Yes | Must match the folder name |
| `description` | Yes | Short description (shown in UI skills panel) |
| `distribution` | No | `public` makes it shareable; omit for private |

## How the agent reads SKILL.md

The agent processes the file top to bottom:

- **Bash blocks** — executed verbatim as shell scripts
- **Markdown prose** — read as instructions for reasoning and branching
- **Step headings** — signal distinct phases; the agent waits for bash output before proceeding

This means you can write conditional logic in prose:

```markdown
If `CONTAINER` is empty, tell the user the stack is not running and offer to run `/drupal-serve` first.
If `CONTAINER` is set, continue to Step 2.

Accepting parameters

The agent extracts parameters from the user's message and passes them as $1, $2, etc.:

MODULE="${1:-}"
if [[ -z "$MODULE" ]]; then
  echo "❌ Provide a module name. Example: /drupal-install token"
  exit 1
fi

Docker awareness pattern

Most Drupal skills need to run commands inside the PHP container or fall back to local binaries. Use this pattern consistently:

PHP_CONTAINER=$(docker ps --filter "status=running" --format '{{.Names}}' 2>/dev/null | grep -E "drupal.*(php|fpm)" | head -1)

if [[ -n "$PHP_CONTAINER" ]]; then
  DRUSH="docker exec -i -w /var/www/html $PHP_CONTAINER vendor/bin/drush"
elif [[ -x "vendor/bin/drush" ]]; then
  DRUSH="vendor/bin/drush"
else
  echo "❌ Drush not found. Is the stack running? Try /drupal-serve"
  exit 1
fi

Branching with flags

To let the agent branch based on detected state, emit a variable in the bash output and reference it in prose:

if [[ -d "/workspace/drupal" ]]; then
  echo "PROJECT_EXISTS=true"
else
  echo "PROJECT_EXISTS=false"
fi

Then in the prose after the block:

If `PROJECT_EXISTS=true`, ask the user whether to overwrite before continuing.
If `PROJECT_EXISTS=false`, proceed directly to Step 2.

Installing your skill

Skills in skills/ are synced to config/.pi/skills/ at container startup via entrypoint.sh. After adding a new skill:

  1. Place SKILL.md in skills/my-skill/
  2. Restart the container: docker compose restart
  3. Test it: type /my-skill in the chat

For immediate testing without restart, copy manually:

docker cp skills/my-skill/ docker-drupalclaw-1:/config/.pi/skills/

Example minimal skill

---
name: drupal-version
description: Show the installed Drupal core version.
distribution: public
---

# drupal-version

Shows the Drupal core version.

## Step 1 — Get version

```bash
PHP_CONTAINER=$(docker ps --filter "status=running" --format '{{.Names}}' 2>/dev/null | grep -E "drupal.*(php|fpm)" | head -1)
if [[ -n "$PHP_CONTAINER" ]]; then
  docker exec -i -w /var/www/html "$PHP_CONTAINER" vendor/bin/drush core:status --field=drupal-version
else
  echo "❌ Stack not running. Start it with /drupal-serve"
fi

Show the version to the user.

Clone this wiki locally