Creating a Custom Skill - PauloCarv/drupalclaw-project GitHub Wiki

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" ](/PauloCarv/drupalclaw-project/wiki/--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" ](/PauloCarv/drupalclaw-project/wiki/--n-"$PHP_CONTAINER"-); then
  DRUSH="docker exec -i -w /var/www/html $PHP_CONTAINER vendor/bin/drush"
elif [ -x "vendor/bin/drush" ](/PauloCarv/drupalclaw-project/wiki/--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" ](/PauloCarv/drupalclaw-project/wiki/--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" ](/PauloCarv/drupalclaw-project/wiki/--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.