How to Write Custom OpenClaw Skills for Slack Workflows

A practical guide to writing custom OpenClaw skills that work in Slack, covering the YAML + Markdown skill format, Slack-specific triggers, channel posting, and thread handling.

Skills Are What Make OpenClaw Yours

Out of the box, OpenClaw is smart but generic. It can answer questions, draft messages, and interact with connected tools. But it doesn't know that when your team says "ship it" they mean merge to main, deploy to staging, run the smoke tests, and post a summary in #releases. That's a skill. And writing skills is how you turn a general-purpose AI agent into one that knows how your team actually works.

Skills in OpenClaw are defined using a combination of YAML (for structure and configuration) and Markdown (for the natural language instructions the agent follows). No Python. No JavaScript. If you can write a clear set of instructions for a human, you can write a skill.

Anatomy of a Skill File

Every skill is a single file. The top section is YAML frontmatter that defines metadata and configuration. The bottom section is Markdown that tells the agent what to do. Here's the basic structure:

---
name: weekly_standup_summary
description: Generates a weekly standup summary from team updates
trigger:
  type: cron
  schedule: "0 17 * * 5"  # Every Friday at 5pm
  channel: "#engineering-standup"
inputs:
  - name: team
    type: string
    default: "engineering"
tools:
  - slack
  - linear
  - notion
---

# Weekly Standup Summary

You are generating a standup summary for the {{team}} team.

## Steps

1. Read all messages posted in #engineering-standup this week
   (Monday through today)
2. For each team member who posted, extract:
   - What they completed
   - What they're working on
   - Any blockers they mentioned
3. Check Linear for tickets that were moved to "Done" this week
   by anyone on the team
4. Create a summary with the following format:
   - **Completed this week** (grouped by person)
   - **In progress** (grouped by person)
   - **Blockers** (highlighted, with suggested actions)
   - **Linear tickets closed:** [count]
5. Post the summary to #engineering-standup as a new message
   (not in a thread)

That's a complete skill. The YAML tells OpenClaw when to run it, what tools it needs, and what inputs it accepts. The Markdown tells it exactly what to do. The agent follows the instructions like a capable human would — it understands context, handles edge cases, and formats the output intelligently.

Triggers: Making Skills React to Slack

Skills need triggers. Here are the types that work in Slack:

Cron Triggers

Run the skill on a schedule. Standard cron syntax.

trigger:
  type: cron
  schedule: "0 9 * * 1-5"  # Weekdays at 9am
  channel: "#team-updates"

The channel field tells the agent where to post the output. Without it, the skill runs but the result goes nowhere (useful for skills that only write to external tools, not Slack).

Mention Triggers

Run when someone @mentions the bot with specific keywords.

trigger:
  type: mention
  match: "deploy report"

The match field uses natural language matching, not exact strings. So "give me a deploy report" or "show me deploy stats" would both trigger this skill. OpenClaw's language model handles the fuzzy matching.

Channel Message Triggers

Run when any message is posted in a specific channel.

trigger:
  type: channel_message
  channel: "#support-triage"
  filter: "contains attachment OR mentions 'urgent'"

This is how you build reactive workflows — the agent watches a channel and acts when certain patterns appear. The filter is optional; without it, the skill triggers on every message in the channel.

Reaction Triggers

Run when someone adds a specific emoji reaction to a message.

trigger:
  type: reaction
  emoji: "ticket"
  channel: "#customer-feedback"

This is extremely useful. Someone in #customer-feedback reacts with :ticket: on a customer's message, and OpenClaw automatically creates a Zendesk ticket from the message content. No forms to fill out. No context switching.

Working with Channels and Threads

Slack's threading model matters for skills. You need to tell the agent whether to post in the main channel, reply in a thread, or create a new thread.

Posting to a Channel

## Output
Post your response to #engineering-standup as a top-level message.

Replying in a Thread

## Output
Reply in the same thread where this skill was triggered.
Do not post to the main channel.

Creating a New Thread

## Output
Post a brief summary to #incidents as a top-level message,
then reply to your own message with the detailed breakdown
in a thread.

Thread handling matters because nobody wants a bot spamming a busy channel with walls of text. Use threads for detailed output and top-level messages for summaries and alerts.

Variables and Dynamic Content

Skills support variables using double-brace syntax: {{variable_name}}. Variables can come from:

  • Inputs: Defined in the YAML frontmatter, provided by the user at trigger time
  • Trigger context: Automatically available — things like {{trigger.user}}, {{trigger.channel}}, {{trigger.message}}, {{trigger.timestamp}}
  • Tool outputs: Results from previous steps that can be referenced in later steps
---
name: create_incident
trigger:
  type: mention
  match: "create incident"
inputs:
  - name: severity
    type: string
    options: ["P1", "P2", "P3"]
  - name: description
    type: string
---

# Create Incident

{{trigger.user}} has reported a {{severity}} incident.

## Steps

1. Create a new Slack channel named #incident-{{timestamp}}-{{severity}}
2. Invite {{trigger.user}} and the current on-call engineer from PagerDuty
3. Post the incident details: {{description}}
4. Create a Linear ticket tagged "incident" with severity {{severity}}
5. If severity is P1, also page the engineering manager via PagerDuty
6. Post a summary in #incidents with a link to the new channel

Error Handling

Skills should tell the agent what to do when things go wrong. Add an error handling section to your Markdown:

## Error Handling

- If Linear is unreachable, skip ticket creation and note it in the output
- If the on-call schedule can't be retrieved, tag @eng-lead instead
- If channel creation fails (name conflict), append a random suffix
- Always post a confirmation message, even if some steps failed.
  List what worked and what didn't.

This is one of the advantages of natural language skill definitions. You don't need try/catch blocks or error codes. You describe what should happen in plain English and the agent follows through.

Testing Skills

Before deploying a skill to your whole team, test it. The easiest way:

  1. Create a private channel like #skill-testing
  2. Add the OpenClaw bot
  3. Trigger the skill manually and watch what happens
  4. Check the audit log for any errors or unexpected behavior
  5. Iterate on the Markdown instructions until the output matches what you want

Testing in a private channel means nobody sees the false starts and weird outputs that happen while you're tuning the instructions. Once it's working, deploy it to the real channel.

Real-World Skill Examples

PR Review Reminder

---
name: pr_review_reminder
trigger:
  type: cron
  schedule: "0 10 * * 1-5"
  channel: "#engineering"
tools:
  - github
  - slack
---

# PR Review Reminder

Check GitHub for open PRs in our main repositories that have been
waiting for review for more than 24 hours.

For each stale PR:
- Note the author, title, and how long it's been open
- Check if a reviewer has been assigned

Post a summary to #engineering with the format:
"These PRs need attention: [list with links]"

Tag the assigned reviewer for each PR. If no reviewer is assigned,
tag the team lead.

Customer Feedback Router

---
name: feedback_router
trigger:
  type: reaction
  emoji: "memo"
  channel: "#customer-calls"
tools:
  - notion
  - slack
---

# Route Customer Feedback

When someone reacts with :memo: to a message in #customer-calls:

1. Read the message content
2. Classify the feedback: bug report, feature request, praise, or complaint
3. Create a new entry in the "Customer Feedback" Notion database with:
   - Feedback text
   - Category
   - Date
   - Source channel and link to original message
   - Reported by: {{trigger.user}}
4. Reply in a thread confirming the feedback was logged
5. If it's a bug report, also post in #product-bugs

Skill Organization

As your skill library grows, keep them organized:

  • Name skills with a clear prefix: support_, eng_, sales_, hr_
  • One skill per file. Don't try to combine unrelated workflows.
  • Document each skill with a clear description in the YAML. Your future self will thank you.
  • Version control your skills in a Git repo. They're just text files; they diff beautifully.

For more on skill templates you can start from, check out our 20 ready-to-use skill templates. And for deeper patterns around skill variables, see the skill variables guide.

The Skill Mindset

Here's the thing that takes most teams a few weeks to internalize: any time you find yourself doing the same sequence of steps in response to the same kind of event, that's a skill. It doesn't have to be complicated. A skill that creates a Slack channel and invites three people when someone says "kickoff meeting" saves five minutes every time it runs. Over a year, that's hours.

Start with the workflow that annoys you the most. Write a skill for it. Test it. Deploy it. Then do the next one. The compounding effect is real: six months from now, your Slack workspace will feel like it runs itself.