Cloodot

Creating Skills

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

Create a SkillSet and deploy skills with 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 for one or more skills — JavaScript functions the AI agent can call during conversations. Building one is a two-step process:

  1. Create the SkillSet — name, description, visibility.
  2. Create a version — add skills and configuration definitions, then deploy.

Each version is an immutable snapshot. Creating a new version automatically makes it the active one.


Plan the skill

Before writing code, answer four questions:

  • 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:

  • 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
parametersInputs the AI agent extracted, matching your parameters schema
configNon-sensitive configuration values set during install (URLs, options, etc.)
secretsSensitive config fields (API keys, tokens) — read credentials here, not from config
contextConversation and organization context

Basic example

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

  const res = await fetch(`${config.apiEndpoint}/orders/${orderId}`, {
    headers: { 'Authorization': `Bearer ${secrets.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, secrets, parameters } = input

  const res = await fetch(`${config.apiEndpoint}/products?q=${parameters.query}`, {
    headers: { 'Authorization': `Bearer ${secrets.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 code validation, schema editors, and AI-powered fix suggestions.

1. Create the SkillSet

  1. Go to AI Settings → Skills.
  2. Click Create New.
  3. Fill in:
    • Name — display name (1–100 characters)
    • Slug — URL-friendly identifier, auto-generated from the name if you leave it blank. Lowercase letters, numbers, and underscores only, max 64 characters.
    • Tagline — short summary (max 200 characters)
    • Description — what the SkillSet does (1–1000 characters)
    • VisibilityPRIVATE (your organization only). Publishing to the public marketplace isn't available from the dashboard yet; use the MCP server or Developer API to create a PUBLIC SkillSet.
  4. Optionally upload a logo.
  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 agent 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 for the inputs the AI agent should extract
    • Response — JSON Schema for the handler's output

    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. Fix any errors the live validator 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 and select a persona.
  2. Open the Skills tab.
  3. Enable the SkillSet.
  4. 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 — Claude Code, Cursor, Windsurf, or any tool that speaks the Model Context Protocol.

Connect

Server URLhttps://developers.cloodot.com/mcp

Authentication — OAuth 2.0. Your MCP client handles the OAuth flow automatically using 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 ships with full input schemas, so your MCP client surfaces required fields and validates inputs automatically. The same field limits from Skill definition limits 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

Every skill handler must return an ActionResponse object that matches 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 agent as tool output. The AI agent reads it to compose a natural-language reply to the user. Keep it informative and concise.
  • message — sent as a direct assistant message, bypassing the AI agent.
  • response.text — text content shown in the chat alongside the AI agent's reply.
  • response.buttons — clickable quick-reply buttons below the message. Tapping one sends payload back as a new message.
  • response.carousel — horizontally scrollable cards with optional image, title, subtitle, and action buttons.
  • response.imageUrl / response.documentUrl — media attachments. Both 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

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. Masks the value in the UI/API responses and delivers it to your handler via input.secrets instead of input.config.

Troubleshooting

Handler not found

Error — "handler function not found"

Define an async handler function in your skill code:

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

Configuration not available

Errorconfig.apiKey (or secrets.apiKey) is undefined

  1. Confirm the configuration key is defined in configDefinitions.
  2. Confirm the SkillSet is installed and configured with values.
  3. Make sure the key in your config definition matches what you read in code.
  4. Fields marked isSensitive arrive in input.secrets, not input.config.

Skill not appearing in conversations

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

Invalid response

If your handler returns something that doesn't match the ActionResponse format (for example, missing prompt), execution fails. At minimum, always return { prompt: "..." }.

Next steps

On this page