Cloodot

Creating Skills

Build and deploy skills using the Dashboard, MCP server, or Developer API

This guide walks you through creating a SkillSet and deploying skills. You can use any of these three methods:

  • Dashboard — visual editor with built-in code validation
  • MCP Server — programmatic access from AI coding assistants
  • Developer API — REST API for automation and CI/CD

A SkillSet is a container that holds one or more skills — JavaScript functions your AI agent can call during conversations. Creating a SkillSet is a two-step process:

  1. Create the SkillSet — define its name, description, and visibility
  2. Create a Version — add your skills, configuration definitions, and deploy

Each version is an immutable snapshot. Creating a new version automatically deploys it as the active version.


Plan Your Skill

Before writing code, define what your skill does:

  • What problem does it solve? (e.g., look up an order status)
  • What inputs does it need? (e.g., order ID)
  • What should it return? (e.g., status, delivery date, tracking URL)
  • Does it need configuration? (e.g., API keys, endpoint URLs)

Example: Order Status Skill

We'll build a skill that checks the status of a customer's order. It needs:

  • Input: Order ID (required), Customer ID (optional)
  • Output: Status message, current status, estimated delivery
  • Config: API endpoint URL, API key

Write the Handler Function

Every skill requires an async function handler(input) that receives:

PropertyDescription
parametersInput values extracted by the AI, matching your parameters schema
configConfiguration values set during installation (API keys, URLs, etc.)
contextConversation and organization context

Basic Example

async function handler(input) {
  const { config, parameters } = input
  const { orderId } = parameters

  const res = await fetch(`${config.apiEndpoint}/orders/${orderId}`, {
    headers: { 'Authorization': `Bearer ${config.apiKey}` }
  })

  if (!res.ok) {
    return {
      prompt: `Failed to look up order ${orderId}: ${res.statusText}`
    }
  }

  const order = await res.json()

  return {
    prompt: `Order ${orderId} is currently ${order.status}. Estimated delivery: ${order.estimatedDelivery}.`,
    response: {
      text: `Order #${orderId}: ${order.status}`,
      buttons: [
        { label: "Track Package", payload: "TRACK_PACKAGE" },
        { label: "Request Return", payload: "REQUEST_RETURN" }
      ]
    }
  }
}
async function handler(input) {
  const { config, parameters } = input

  const res = await fetch(`${config.apiEndpoint}/products?q=${parameters.query}`, {
    headers: { 'Authorization': `Bearer ${config.apiKey}` }
  })
  const { products } = await res.json()

  return {
    prompt: `Found ${products.length} products matching "${parameters.query}".`,
    response: {
      carousel: products.slice(0, 5).map(p => ({
        title: p.name,
        subtitle: `$${p.price}`,
        imageUrl: p.imageUrl,
        buttons: [
          { type: "web_url", title: "View", url: p.url },
          { type: "postback", title: "Add to Cart", payload: `ADD_${p.id}` }
        ]
      }))
    }
  }
}

Via Dashboard

The Dashboard provides a visual editor with built-in code validation, schema editors, and AI-powered fix suggestions.

1. Create the SkillSet

  1. Go to AI Settings → Skills
  2. Click Create New SkillSet
  3. Fill in the details:
    • Name: Display name (1–100 characters)
    • Slug: URL-friendly identifier (auto-generated from name if left blank). Lowercase letters, numbers, and underscores only, max 64 characters.
    • Tagline: Short summary (max 200 characters)
    • Description: What the SkillSet does (1–1000 characters)
    • Visibility: PRIVATE (your organization only) or PUBLIC (marketplace)
  4. Optionally upload a logo image
  5. Save

2. Create a Version with Skills

  1. Open your SkillSet and go to the code editor

  2. For each skill, fill in:

    Metadata:

    • Name — display name (1–100 characters)
    • Slug — identifier (1–64 characters, ^[a-z0-9_]+$)
    • Description — what it does (1–500 characters)
    • Prompt — tell the AI when and how to use this skill (1–2000 characters)
    • KindEXECUTE (performs an action) or SEARCH (retrieves data)

    Code:

    • Handler Code — your JavaScript handler function (max 50 KB)

    Schemas (JSON editors):

    • Parameters — JSON Schema defining the inputs the AI should extract
    • Response — JSON Schema describing the handler's output structure

    Optional:

    • Buttons — quick reply buttons (label max 50 chars, payload max 200 chars)
  3. Add Configuration Definitions if your skill needs API keys or settings (see Configuration Types)

  4. The editor validates your code in real-time — fix any errors it flags

  5. Enter a changelog message and publish

3. Install and Configure

  1. Go to AI Settings → Skills
  2. Find your SkillSet and click Install
  3. Fill in the required configuration values (API key, endpoint, etc.)
  4. Save

4. Connect to a Persona

  1. Go to AI Settings → Personas
  2. Select the persona
  3. Go to the Skills tab
  4. Enable the SkillSet
  5. Test in a conversation (try: "check the status of order ORD-12345")

Via MCP Server

The Cloodot MCP server lets you manage SkillSets from any MCP-compatible client — AI coding assistants like Claude Code, Cursor, Windsurf, or any tool that supports the Model Context Protocol.

Connecting

Server URL: https://developers.cloodot.com/mcp

Authentication: OAuth 2.0 — your MCP client handles the OAuth flow automatically. The server advertises its auth configuration via the standard /.well-known/oauth-protected-resource endpoint.

Available Tools

ToolDescription
create_skillsetCreate a new SkillSet
update_skillsetUpdate SkillSet metadata
delete_skillsetPermanently delete a SkillSet
list_skillsetsList visible SkillSets (owned + public)
get_skillsetGet a specific SkillSet with deployed version
create_skillset_versionCreate and deploy a new version with skills
list_skillset_versionsList all versions (newest first)
install_skillsetInstall a SkillSet into your organization
uninstall_skillsetRemove installation and config values
update_skillset_configUpdate configuration values for an installed SkillSet

Each tool includes full input schemas — your MCP client will present the required fields and validate inputs automatically. The same field limits from the Skill Definition Limits section apply.


Via Developer API

The Developer API is available at https://developers.cloodot.com. All endpoints require an API key sent via the x-api-key header.

For the complete API reference with request/response schemas, visit the interactive documentation at:

https://developers.cloodot.com/api/v1/reference

Quick Start

Create a SkillSet:

curl -X POST https://developers.cloodot.com/api/v1/skillsets \
  -H "x-api-key: cloodot_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Order Management",
    "description": "Skills for checking order status and managing shipments",
    "visibility": "PRIVATE"
  }'

Create a version (auto-deploys):

curl -X POST https://developers.cloodot.com/api/v1/skillsets/SKILLSET_ID/versions \
  -H "x-api-key: cloodot_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "changeLog": "...", "skills": [...], "configDefinitions": [...] }'

Install and configure:

curl -X POST https://developers.cloodot.com/api/v1/skillsets/SKILLSET_ID/install \
  -H "x-api-key: cloodot_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{}'

curl -X PUT https://developers.cloodot.com/api/v1/skillsets/SKILLSET_ID/config \
  -H "x-api-key: cloodot_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "config": { "apiEndpoint": "https://api.example.com", "apiKey": "sk-..." } }'

Available Endpoints

MethodEndpointDescription
GET/api/v1/skillsetsList SkillSets
POST/api/v1/skillsetsCreate a SkillSet
GET/api/v1/skillsets/{id}Get a SkillSet
PUT/api/v1/skillsets/{id}Update a SkillSet
DELETE/api/v1/skillsets/{id}Delete a SkillSet
GET/api/v1/skillsets/{id}/versionsList versions
POST/api/v1/skillsets/{id}/versionsCreate a version (auto-deploys)
POST/api/v1/skillsets/{id}/installInstall a SkillSet
POST/api/v1/skillsets/{id}/uninstallUninstall a SkillSet
PUT/api/v1/skillsets/{id}/configUpdate config values

ActionResponse Reference

The ActionResponse is the required return format for all skill handlers. Your handler must return an object conforming to this schema.

Schema

{
  prompt: string,              // Required
  message?: string,            // Optional
  data?: any,                  // Optional
  response?: {                 // Optional
    text?: string,
    buttons?: Array<{ label: string, payload: string }>,
    carousel?: Array<CarouselItem>,
    imageUrl?: string,
    documentUrl?: string
  }
}

Field Reference

FieldTypeRequiredLimitsDescription
promptstringYesNo max lengthText returned to the AI as context for its reply
messagestringNoNo max lengthDirect assistant message in the conversation
dataanyNoAdditional structured data
responseobjectNoRich response content (see below)
response.textstringNoNo max lengthText content displayed to the end user
response.buttonsarrayNoNo max array lengthQuick reply buttons
response.buttons[].labelstringYesMax 20 charactersButton text shown to the user
response.buttons[].payloadstringYesMax 20 charactersValue sent back when the button is clicked
response.carouselarrayNoNo max array lengthCarousel cards
response.imageUrlstringNoMust be a valid HTTPS URLImage sent as an attachment
response.documentUrlstringNoMust be a valid HTTPS URLDocument/file sent as an attachment
FieldTypeRequiredDescription
titlestringYesCard title
subtitlestringNoCard subtitle
imageUrlstringNoImage URL for the card
defaultActionUrlstringNoURL opened when the card is tapped
buttonsarrayNoCard-level action buttons
buttons[].typestringYes"web_url" or "postback"
buttons[].titlestringYesButton label
buttons[].urlstringNoURL to open (for web_url type)
buttons[].payloadstringNoPayload sent back (for postback type)

How Fields Are Used

  • prompt — Fed back to the AI model as tool output. The AI reads this to formulate a natural language response to the user. Keep it informative and concise.
  • message — Sent as a direct assistant message, bypassing AI generation.
  • response.text — Displayed as text content in the chat alongside the AI's response.
  • response.buttons — Rendered as clickable quick reply buttons below the message. When clicked, the payload is sent back as a new message.
  • response.carousel — Rendered as horizontally scrollable cards, each with optional image, title, subtitle, and action buttons.
  • response.imageUrl / response.documentUrl — Sent as media attachments in the chat. Must be HTTPS URLs.

Minimal Return

return { prompt: "Order ORD-123 is shipped and arriving tomorrow." }

Full Return

return {
  prompt: "Found 3 products matching the search.",
  response: {
    text: "Here are the top results:",
    buttons: [
      { label: "Show More", payload: "SHOW_MORE" }
    ],
    carousel: [
      {
        title: "Widget Pro",
        subtitle: "$29.99",
        imageUrl: "https://example.com/widget.png",
        buttons: [
          { type: "web_url", title: "View", url: "https://example.com/widget" },
          { type: "postback", title: "Buy Now", payload: "BUY_WIDGET_PRO" }
        ]
      }
    ],
    imageUrl: "https://example.com/promo-banner.png"
  }
}

Skill Definition Limits

Reference for all field limits when creating a skill version:

Skill Fields

FieldTypeRequiredLimits
slugstringYes1–64 chars, pattern: ^[a-z0-9_]+$
namestringYes1–100 chars
descriptionstringYes1–500 chars
kindstringNo"EXECUTE" (default) or "SEARCH"
promptstringYes1–2000 chars
definitionstringYes1–50,000 chars (~50 KB)
parametersobjectNoValid JSON Schema, defaults to {}
responseobjectNoValid JSON Schema, defaults to {}
buttonsarrayNoArray of {label, payload}
buttons[].labelstringYes1–50 chars
buttons[].payloadstringYes1–200 chars

SkillSet Fields

FieldTypeRequiredLimits
namestringYes1–100 chars
slugstringNo1–64 chars, pattern: ^[a-z0-9_]+$, auto-generated if omitted
taglinestringNoMax 200 chars
descriptionstringYes1–1000 chars
visibilitystringNo"PUBLIC" or "PRIVATE" (default)
logoImageUrlstringNoValid URL
bannerImageUrlstringNoValid URL

Version Fields

FieldTypeRequiredLimits
changeLogstringYes1–1000 chars
skillsarrayYesAt least 1 skill

Configuration Types

FieldTypeRequiredLimits
keystringYes1–50 chars (camelCase recommended)
labelstringYes1–100 chars
typestringYesSTRING, NUMBER, BOOLEAN, SELECT, MULTI_SELECT, SECRET
descriptionstringNoMax 500 chars
requiredbooleanNoDefaults to false
defaultValuestringNo
ordernumberNoInteger, defaults to 0
optionsarrayNoArray of strings (for SELECT/MULTI_SELECT)
validationstringNoMax 200 chars, must be a valid regular expression
isSensitivebooleanNoDefaults to false. Encrypts and masks the value in UI.

Troubleshooting

Handler Not Found

Error: "handler function not found"

Your skill code must define an async handler function:

async function handler(input) {
  // ...
}

Configuration Not Available

Error: config.apiKey is undefined

  1. Ensure the configuration key is defined in configDefinitions
  2. Verify the SkillSet is installed and configured with values
  3. Check that the key in your config definition matches what you access in code

Skill Not Appearing in Conversations

  1. Confirm the SkillSet version is deployed (creating a version auto-deploys)
  2. Check the SkillSet is installed in your organization
  3. Verify the persona has the SkillSet enabled
  4. Make sure the prompt field clearly describes when the AI should use the skill

Invalid Response

If your handler returns a value that doesn't match the ActionResponse format (e.g., missing the prompt field), the execution will fail. Always return at least { prompt: "..." }.

Next Steps

On this page