Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ npx create-cloudinary-next

## Requirements

- **Node.js** — use a [current LTS](https://nodejs.org/en/about/previous-releases) release.
- **Node.js 22** or later
- A **Cloudinary account**
- [Sign up for free](https://cld.media/nextregisterreadme)
- Your cloud name is in your [dashboard](https://console.cloudinary.com/app/home/dashboard)
Expand Down
16 changes: 13 additions & 3 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { existsSync, mkdirSync, writeFileSync, readFileSync, cpSync, mkdtempSync, rmSync } from 'fs';
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, cpSync, mkdtempSync, rmSync } from 'fs';
import { tmpdir } from 'os';
import { spawnSync } from 'child_process';
import { parseArgs } from 'node:util';
Expand Down Expand Up @@ -89,8 +89,15 @@ function readTemplate(relativePath) {
}

function findSkillSourceDir(baseDir, skillName) {
const candidates = [join(baseDir, 'skills', skillName), join(baseDir, skillName)];
return candidates.find((candidate) => existsSync(candidate));
const skillsDir = join(baseDir, 'skills');
// The skills repo groups skills into category folders (skills/<category>/<name>)
const categoryCandidates = existsSync(skillsDir)
? readdirSync(skillsDir, { withFileTypes: true })
.filter((entry) => entry.isDirectory())
.map((entry) => join(skillsDir, entry.name, skillName))
: [];
const candidates = [join(skillsDir, skillName), ...categoryCandidates, join(baseDir, skillName)];
return candidates.find((candidate) => existsSync(join(candidate, 'SKILL.md')));
}

function writeFileEnsureDir(filePath, content) {
Expand Down Expand Up @@ -166,6 +173,9 @@ function writeSkill(projectPath, aiTools) {
}

if (!sourceDir) {
if (remoteInstallAvailable) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sits inside for (const targetRoot of targetRoots). If the user picks Claude plus Cursor/Copilot/Generic, there are two target folders (.claude/skills and .agents/skills), so every missing skill gets the same warning twice.

Instead we can work out sourceDir for each skill once, before the targetRoots loop, and warn there.

console.log(chalk.yellow(` ${skillName} not found in the Cloudinary skills repo; using the bundled local backup.`));
}
sourceDir = localFallbacks[skillName];
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"author": "Cloudinary, Inc.",
"license": "MIT",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to update lockfle to match version

"engines": {
"node": ">=18.0.0"
"node": ">=22.0.0"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

engines doesn't enforce the Node.js version by default but is only a warning, or nothing at all, unless they've turned on engine-strict.
We can have the CLI check process.versions.node and stop or warn with a clear message

},
"scripts": {
"semantic-release": "semantic-release"
Expand Down
95 changes: 76 additions & 19 deletions templates/skills/cloudinary-docs/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,88 @@
---
name: cloudinary-docs
description: look up the latest cloudinary docs and official references. use when answering cloudinary questions or implementing uploads, optimization, transformations, apis, webhooks, or integrations.
description: Looks up implementation details in the latest Cloudinary docs via the relevant llms.txt file. Use when building code or answering questions relating to image or video uploads, management, SDKs, APIs, webhooks, or integrations. For topics covered by a specialized Cloudinary skill, prefer that skill. Use this skill alongside it when the full use-case requires capabilities outside that skill's scope.
license: MIT
metadata:
author: cloudinary
version: '1.1.0'
---

# Cloudinary Docs
# Cloudinary Documentation

## Purpose
Helps developers integrate Cloudinary into their applications by providing documentation and code examples retrieved directly from the agent-optimized markdown files in the Cloudinary documentation.

Use this skill when you need current Cloudinary documentation instead of memory or stale examples.
## When to Use

## Core workflow
- When a user asks questions or requests code implementation relating to image or video upload, management, SDKs, APIs, webhooks, or integrations
- For topics covered by a more specialized Cloudinary skill (e.g. transformations, React SDK): prefer that skill. Use this skill alongside it when the full use-case also requires capabilities outside that skill's scope.
- General Cloudinary documentation lookup (account settings, webhooks, DAM features)
- Looking up specific Cloudinary API endpoints or SDK methods
- When a specialized Cloudinary skill handles part of a use-case, use this skill to cover the remaining capabilities it doesn't address, not as a substitute for it.

1. Identify the Cloudinary product area first.
2. Prefer the latest official docs and llms.txt over examples copied from old code.
3. Verify package names, environment variables, event names, and configuration shapes before coding.
4. When a detail is version-sensitive, check the official docs instead of guessing.
## Sub-file Index Overview

## Use it for
The main documentation llms.txt file is split into product-specific sub-files. **Go directly to the relevant sub-file** according to the descriptions below. Do not fetch the main llms.txt first unless the topic spans multiple products or you are unsure.

- Uploads and upload presets
- Delivery, optimization, and transformation questions
- SDK and API usage
- Webhooks and server-side workflows
- Troubleshooting and version-sensitive behavior
| Product | Topic | Sub-file URL |
|---|---|---|
| Image & Video APIs | Image/video uploads, transformations, optimization, SDKs, APIs, webhooks, add-ons, embedding widgets or players in apps, or any programmatic/automation/at-scale image and video requirements | https://cloudinary.com/documentation/llms-image-and-video-apis.txt?install_source=skillspack&referrer=docs-skill |
| Cloudinary Assets (DAM) | Digital Asset Management (DAM), Media Library, folders, metadata, collections, creative workflows, portals, digital rights, or any Cloudinary Console or UI-based asset management needs | https://cloudinary.com/documentation/llms-cloudinary-assets.txt?install_source=skillspack&referrer=docs-skill |
| MediaFlows | PowerFlows, EasyFlows, workflow automation, flow blocks | https://cloudinary.com/documentation/llms-mediaflows.txt?install_source=skillspack&referrer=docs-skill |
| Integrations | Cloudinary integrations with 3rd party apps (WordPress, Shopify, Contentful, Salesforce, Adobe, etc.) or questions about implementing new integrations | https://cloudinary.com/documentation/llms-integrations.txt?install_source=skillspack&referrer=docs-skill |
| Cross-product or unsure | Multiple products, general, or unclear topic | https://cloudinary.com/documentation/llms.txt?install_source=skillspack&referrer=docs-skill |

## Rules
## Instructions

- Do not invent API names or prop names.
- Prefer official Cloudinary docs and reference pages.
- If a question spans multiple Cloudinary products, split it into smaller doc lookups by topic.
**Note:** If a more specialized Cloudinary-specific skill covers the user's topic, defer to that skill first. Invoke this docs skill in addition, not as a substitute, and only if the full use-case also requires capabilities outside that skill's scope.

When using this skill to answer image and video upload, management, optimization, or transformation questions or when implementing Cloudinary code:

1. **Identify the product area**: Refer to the [Sub-file Index table](#sub-file-index-overview) above and identify the matching row.
2. **Fetch the relevant sub-file directly per the table above** (skip the main llms.txt unless the topic is cross-product or unclear)
3. **Analyze the sub-file** to identify which specific documentation URLs are most relevant
4. **Retrieve** those specific markdown documentation URLs (you can make multiple calls if needed)
5. **Use the fetched documentation** to provide a comprehensive, accurate answer or code implementation.

## Example Workflows

**Example 1: SDK question**
- User asks: "How do I install and use the Node.js SDK for Cloudinary?"
- Topic maps to Image & Video APIs → fetch https://cloudinary.com/documentation/llms-image-and-video-apis.txt?install_source=skillspack&referrer=docs-skill
- Identify SDK-related pages and provide installation instructions and usage examples or help implement the request in the user's code.

**Example 2: DAM question**
- User asks: "How do I set up approval workflows for assets in the Media Library?"
- Topic maps to Cloudinary Assets (DAM) → fetch https://cloudinary.com/documentation/llms-cloudinary-assets.txt?install_source=skillspack&referrer=docs-skill
- Identify relevant pages like "dam_admin_creative_approval_flows.md"
- Fetch the specific documentation and provide setup steps

**Example 3: MediaFlows question**
- User asks: "How do I build a PowerFlow that auto-moderates uploaded images?"
- Topic maps to MediaFlows → fetch https://cloudinary.com/documentation/llms-mediaflows.txt?install_source=skillspack&referrer=docs-skill
- Identify relevant pages like "mediaflows_build_flow.md" or "mediaflows_moderation_powerflow.md"
- Fetch the specific documentation and provide a flow-building walkthrough

**Example 4: Integration question**
- User asks: "How do I connect Cloudinary to my WordPress site?"
- Topic maps to Integrations → fetch https://cloudinary.com/documentation/llms-integrations.txt?install_source=skillspack&referrer=docs-skill
- Identify relevant pages like "wordpress_integration.md"
- Fetch the specific documentation and provide setup instructions

**Example 5: Ambiguous upload question**
- User asks: "How do I upload images to Cloudinary?"
- First, determine whether the user wants to upload **programmatically** (via SDK/API) or **via the Console UI** (DAM)
- If **programmatic** → fetch https://cloudinary.com/documentation/llms-image-and-video-apis.txt?install_source=skillspack&referrer=docs-skill
- Identify relevant pages like "image_upload.md" or "upload_api.md"
- Retrieve those specific pages and provide an answer with code examples
- If **via the Console UI (DAM)** → fetch https://cloudinary.com/documentation/llms-cloudinary-assets.txt?install_source=skillspack&referrer=docs-skill
- Identify relevant pages like "dam_upload_store_assets.md" or "dam_admin_upload_presets.md"
- Retrieve those specific pages and provide step-by-step instructions for uploading via the Media Library.
- If **unable to determine** → fetch https://cloudinary.com/documentation/llms.txt?install_source=skillspack&referrer=docs-skill
- Look at documentation for both Image & Video APIs and Cloudinary Assets products
- Provide an answer covering both programmatic and UI-based upload options

**Example 6: Transformation question (fallback: use only if no specialized skill covers this topic)**
- User asks: "How do I resize and crop images?"
- Topic maps to Image & Video APIs → fetch https://cloudinary.com/documentation/llms-image-and-video-apis.txt?install_source=skillspack&referrer=docs-skill
- Identify relevant pages like "image_transformations.md" or "transformation_reference.md"
- Fetch the specific documentation and provide transformation syntax and examples or help implement the request in the user's code.
Loading