How to Write Custom Skills for OpenClaw in Slack

Learn how to build and deploy custom skills for OpenClaw inside your Slack workspace, from structuring your skill manifest to handling tool calls and persistent memory — with practical code examples throughout.

What Are Custom Skills, and Why Do They Matter?

Out of the box, SlackClaw connects your Slack workspace to 800+ tools via one-click OAuth — GitHub, Linear, Jira, Gmail, Notion, and dozens more. That covers a lot of ground. But every team has workflows that don't fit neatly into a pre-built integration. Maybe you need the agent to query an internal pricing API before drafting a proposal, or automatically tag Linear tickets based on your company's proprietary severity rubric. That's where custom skills come in.

In OpenClaw, a skill is a discrete, callable capability you register with the agent runtime. It tells the agent what the skill does, what parameters it accepts, and how to invoke it. SlackClaw runs OpenClaw on a dedicated server per team, which means your custom skills are isolated, version-controlled, and won't interfere with anyone else's setup. Think of it as giving your AI coworker a new tool in its toolbelt — one you designed specifically for how your team operates.

Anatomy of an OpenClaw Skill

Every skill in OpenClaw is defined by three components: a manifest, a handler function, and optionally a memory hook. Let's break each one down before we write our first skill end-to-end.

The Skill Manifest

The manifest is a JSON-like descriptor that the agent uses to decide when to call your skill and what inputs to pass. It follows OpenAI's function-calling schema, which OpenClaw wraps with additional metadata for routing and permissions.

{
  "name": "get_deal_stage",
  "description": "Looks up the current pipeline stage for a given deal ID in the internal CRM. Use this when a user asks about a deal's status, next steps, or owner.",
  "parameters": {
    "type": "object",
    "properties": {
      "deal_id": {
        "type": "string",
        "description": "The unique deal identifier, e.g. DEAL-1042"
      },
      "include_history": {
        "type": "boolean",
        "description": "If true, returns stage transition history in addition to the current stage.",
        "default": false
      }
    },
    "required": ["deal_id"]
  }
}

The description field is the most important thing you'll write. The agent reads it literally to decide whether this skill is relevant to a user's request. Be specific about the context in which the skill should be used, not just what it does. Vague descriptions lead to missed invocations or, worse, the agent calling your skill when it shouldn't.

The Handler Function

The handler is where your actual business logic lives. In OpenClaw, handlers are async Python functions that receive a validated parameter dict and return either a string or a structured dict that gets serialized back to the agent.

import httpx
from openclaw.skills import skill_handler

@skill_handler(name="get_deal_stage")
async def get_deal_stage(deal_id: str, include_history: bool = False) -> dict:
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"https://crm.internal.yourcompany.com/api/deals/{deal_id}",
            headers={"Authorization": f"Bearer {env('CRM_API_KEY')}"},
            params={"history": include_history}
        )
        response.raise_for_status()
        data = response.json()

    return {
        "deal_id": deal_id,
        "stage": data["current_stage"],
        "owner": data["owner_name"],
        "last_updated": data["updated_at"],
        "history": data.get("stage_history", []) if include_history else []
    }

A few things worth noting here. First, use env() rather than hardcoding secrets — SlackClaw's dedicated server environment lets you store per-team secrets securely in the dashboard under Settings → Environment Variables. Second, return structured dicts rather than pre-formatted strings wherever possible. The agent is better at formatting output for Slack's block kit when it has structured data to work with. Learn more about our pricing page.

Registering Your Skill with SlackClaw

Once your manifest and handler are written, registration is straightforward. Place your skill file inside the /skills directory of your team's OpenClaw workspace repo, then push to the branch connected to your SlackClaw server. Learn more about our integrations directory.

  1. Navigate to your SlackClaw dashboard and open Agent → Skills.
  2. Click Sync from Repository — SlackClaw will pull the latest commit and hot-reload the skill registry without restarting the server.
  3. Verify the skill appears in the registry with a green status indicator. A yellow indicator means the manifest failed schema validation; click it to see the error.
  4. Test the skill directly from the dashboard using the Skill Sandbox before exposing it to your team.

After a successful sync, your Slack agent can call the skill autonomously within any conversation or automated workflow — no further configuration needed.

Using Persistent Memory in Custom Skills

One of SlackClaw's most powerful features is persistent memory — the agent maintains context across conversations, channels, and days. Your custom skills can read from and write to this memory store, which opens up some genuinely interesting possibilities.

Reading from Memory

Imagine a skill that summarizes a Notion document. Instead of re-fetching and re-summarizing the same doc every time a user asks about it, you can check memory first:

from openclaw.skills import skill_handler
from openclaw.memory import get_memory, set_memory

@skill_handler(name="summarize_notion_doc")
async def summarize_notion_doc(page_id: str, force_refresh: bool = False) -> dict:
    cache_key = f"notion_summary:{page_id}"

    if not force_refresh:
        cached = await get_memory(cache_key)
        if cached:
            return {"summary": cached["summary"], "source": "cache"}

    # Fetch and summarize via the Notion integration
    # (OpenClaw handles the OAuth token automatically)
    page_content = await notion.get_page_content(page_id)
    summary = await agent.summarize(page_content)

    await set_memory(cache_key, {"summary": summary}, ttl_hours=24)
    return {"summary": summary, "source": "fresh"}

Writing Contextual State

Memory writes are equally useful for building stateful workflows. A skill that triages incoming GitHub issues, for example, might store the last-seen issue number so it knows where to resume on the next run — no database required, no extra infrastructure.

Pro tip: Namespace your memory keys with the skill name (e.g., triage_bot:last_issue_id) to avoid collisions with other skills or SlackClaw's internal memory entries.

Composing Skills with Built-In Integrations

Custom skills don't have to do everything themselves. Because SlackClaw already has authenticated connections to tools like GitHub, Linear, Jira, and Gmail, your skills can invoke those integrations programmatically via OpenClaw's integration client — no extra auth setup required. For related insights, see OpenClaw Custom Skills: A Complete Tutorial.

from openclaw.integrations import get_client

@skill_handler(name="escalate_to_linear")
async def escalate_to_linear(issue_description: str, severity: str, slack_thread_url: str) -> dict:
    linear = get_client("linear")  # Uses the team's existing OAuth token

    issue = await linear.create_issue(
        title=f"[{severity.upper()}] {issue_description[:80]}",
        description=f"Escalated from Slack: {slack_thread_url}\n\n{issue_description}",
        priority={"critical": 1, "high": 2, "medium": 3}.get(severity, 3),
        team_id=env("LINEAR_TEAM_ID")
    )

    return {"issue_id": issue["id"], "url": issue["url"]}

This pattern — custom business logic layered on top of SlackClaw's 800+ built-in connections — is where the real leverage is. You're not replacing the integrations; you're orchestrating them according to your team's specific rules.

Common Mistakes and How to Avoid Them

  • Overloading a single skill. If your skill does five different things depending on its inputs, the agent will have a hard time deciding when to use it. Split complex skills into smaller, focused ones with clear descriptions.
  • Returning unstructured error strings. Raise exceptions rather than returning error messages as strings. OpenClaw catches exceptions and handles them gracefully; a returned error string looks like a valid result to the agent.
  • Ignoring idempotency. The agent may retry a skill call if it doesn't receive a response in time. Make sure skills that create records (Linear issues, Jira tickets, calendar events) check for duplicates before writing.
  • Skipping the Sandbox. The Skill Sandbox in the SlackClaw dashboard lets you call your skill with arbitrary inputs before it goes live. Use it. A skill that fails silently in production is much harder to debug than one you caught in testing.

Pricing Considerations for Heavy Skill Usage

SlackClaw uses credit-based pricing with no per-seat fees, which means your costs scale with what you actually use rather than how many people are in your workspace. Custom skills consume credits when they trigger agent reasoning — the model deciding whether and how to invoke your skill. Skills that return large payloads or trigger multi-step reasoning chains will use more credits than lightweight lookups.

To keep usage efficient, return only the data the agent actually needs. If your internal CRM returns 40 fields but the agent only ever cares about three of them, filter at the handler level before returning. Smaller context windows mean faster responses and lower credit consumption — a win on both sides.

Where to Go From Here

Custom skills are the fastest path to making SlackClaw feel like it was built specifically for your team. Start with one pain point — a lookup your team does manually five times a day, or a handoff between two tools that always requires copy-pasting — and build a skill around it. Once you see the agent invoking it naturally in conversation, you'll have a clear intuition for where to go next. For related insights, see Create an OpenClaw Runbook for Your Slack Team.

The OpenClaw skill registry, handler API reference, and memory client documentation are all available in the SlackClaw dashboard under Developer Docs. The community forum is also a good place to share skills your team has built — several teams have published reusable skill templates for common patterns like on-call rotation lookups, sprint report generation, and customer health scoring.