agentsclimarketplace

Raycast automator

Skill sacredvoid/skillkit/skills/raycast-automator

A growing collection of AI coding skills for creative and productivity workflows. Image fetching, logo generation, presentations, video/audio processing, local image generation, and more. Works with Claude Code, Cursor, Windsurf, Copilot, and any AI coding assistant.

Install
npx -y skills add sacredvoid/skillkit --skill raycast-automator

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 10 stars10 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when the user asks to automate a task with Raycast, build a Raycast extension, create a Raycast script command, or mentions Raycast in the context of building something. Triggers on: "automate X with Raycast", "build a Raycast extension", "create a raycast script", "make a raycast command", or any task where Raycast is the target platform.

SKILL.md

12.0 KB, as published. Nobody here has run it

Raycast Automator

Build Raycast extensions and script commands from natural language task descriptions. Handles the full lifecycle: analysis, code generation, setup, and dev launch.

Output Directory

All output goes to ~/Documents/raycast-scripts/:

  • Script commands: files directly in the root (e.g., my-script.sh)
  • Extensions: subdirectories (e.g., my-extension/src/index.tsx)

Create the directory if it doesn't exist. For extensions, create the subdirectory named after the extension.

Decision Flow

User describes a task
  │
  ├─ Analyze complexity
  │   ├─ Needs rich UI (lists, forms, grids, detail views)?  → Extension
  │   ├─ Needs OAuth or token management?                     → Extension
  │   ├─ Needs persistent state across runs?                  → Extension
  │   ├─ Needs menu bar presence?                             → Extension
  │   ├─ Needs pagination or streaming data?                  → Extension
  │   ├─ Simple system operation (open, toggle, copy)?        → Script Command
  │   ├─ Opens URL or does clipboard work?                    → Script Command
  │   ├─ Runs a shell command or API call with simple output? → Script Command
  │   └─ 1-3 simple text inputs, no interactive UI?           → Script Command
  │
  ├─ Present recommendation with reasoning to user
  ├─ User confirms or overrides
  │
  ├─ IF Script Command:
  │   ├─ Pick language:
  │   │   ├─ macOS + simple task       → Bash
  │   │   ├─ Windows + simple task     → Batch/PowerShell
  │   │   ├─ Complex logic / API calls → Python
  │   │   └─ Mac-native automation     → AppleScript
  │   ├─ Generate script with full metadata block
  │   ├─ chmod +x the file
  │   ├─ Ensure ~/Documents/raycast-scripts/ is created
  │   └─ Tell user to add script directory in Raycast if first time
  │
  └─ IF Extension:
      ├─ Scaffold project structure
      ├─ Generate package.json with full manifest
      ├─ Generate src/ entry point(s)
      ├─ Run npm install
      ├─ Run npm run dev
      └─ Confirm extension appears in Raycast

Before Writing Code

  1. Read the reference files in reference/ directory of this skill:

    • reference/extension-api.md - for extensions (manifest, UI components, hooks, APIs)
    • reference/script-commands.md - for script commands (metadata, templates, examples)
    • reference/patterns.md - for best practices and common patterns
  2. Check platform: Use uname to detect macOS vs other. This affects:

    • Script language defaults (bash vs bat)
    • Available APIs (MenuBarExtra, BrowserExtension are macOS-only)
    • AppleScript availability

Script Command Generation

Required metadata block (ALWAYS include all of these):

#!/bin/bash

# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title <Title Case Name>
# @raycast.mode <silent|compact|fullOutput|inline>

# Optional parameters:
# @raycast.packageName <Category>
# @raycast.icon <emoji or path>
# @raycast.description <What it does>
# @raycast.needsConfirmation <true for destructive ops>
# @raycast.argument1 { "type": "text", "placeholder": "..." }

Mode selection:

ModeWhen to use
silentOpens URL, clipboard ops, launches app, background task
compactShort confirmation message, quick status
fullOutputMulti-line output, formatted results, logs
inlineLive status display (requires refreshTime, min 10s)

Language shebangs:

LanguageShebangExtension
Bash#!/bin/bash.sh
Python 3#!/usr/bin/env python3.py
Node.js#!/usr/bin/env node.js
AppleScript#!/usr/bin/osascript.applescript
Ruby#!/usr/bin/env ruby.rb
Swift#!/usr/bin/swift.swift

Argument access by language:

LanguageArg 1Arg 2Arg 3
Bash$1$2$3
Pythonsys.argv[1]sys.argv[2]sys.argv[3]
Node.jsprocess.argv[2]process.argv[3]process.argv[4]
AppleScriptitem 1 of argvitem 2 of argvitem 3 of argv
RubyARGV[0]ARGV[1]ARGV[2]
SwiftCommandLine.arguments[1]CommandLine.arguments[2]CommandLine.arguments[3]

Script rules:

  • Max 3 arguments per script
  • Use percentEncoded: true for URL arguments
  • Use needsConfirmation: true for destructive operations
  • Non-zero exit code = failure (last line becomes error message)
  • Scripts run in non-login shell; use #!/bin/bash -l if login shell needed
  • inline mode REQUIRES refreshTime (min 10s)
  • Use absolute paths since PATH may differ from user's shell

Extension Generation

Minimum project structure:

extension-name/
├── package.json          # Manifest (see reference/extension-api.md)
├── tsconfig.json         # TypeScript config
├── src/
│   └── index.tsx         # Main command entry point
└── assets/
    └── icon.png          # 512x512 PNG (or use command-icon.png)

package.json template:

{
  "$schema": "https://www.raycast.com/schemas/extension.json",
  "name": "extension-name",
  "title": "Extension Title",
  "description": "What it does",
  "icon": "command-icon.png",
  "author": "author-name",
  "categories": ["Productivity"],
  "license": "MIT",
  "platforms": ["macOS"],
  "commands": [
    {
      "name": "index",
      "title": "Command Title",
      "description": "What the command does",
      "mode": "view"
    }
  ],
  "dependencies": {
    "@raycast/api": "^1.98.0",
    "@raycast/utils": "^1.19.0"
  },
  "devDependencies": {
    "@raycast/eslint-config": "^1.0.11",
    "typescript": "^5.4.5",
    "@types/node": "22.14.0",
    "@types/react": "19.0.0",
    "eslint": "^8.57.0"
  },
  "scripts": {
    "build": "ray build",
    "dev": "ray dev",
    "fix-lint": "ray lint --fix",
    "lint": "ray lint",
    "prepublishOnly": "echo \"Error: no publish script\" && exit 1",
    "publish": "npx @raycast/api@latest publish"
  }
}

tsconfig.json template:

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "lib": ["ES2023"],
    "module": "Node16",
    "moduleResolution": "node16",
    "target": "ES2022",
    "resolveJsonModule": true,
    "strict": true,
    "jsx": "react-jsx"
  },
  "include": ["src/**/*", "env.d.ts", "raycast-env.d.ts"]
}

Command modes:

ModeExportUse case
viewReact component (default export)Interactive UI with List/Detail/Form/Grid
no-viewAsync function (default export)Background tasks, clipboard ops, no UI
menu-barMenuBarExtra componentPersistent menu bar item (macOS only)

Choosing the right UI component:

ComponentWhen to use
ListSearchable items, most common. Use isShowingDetail for split view
DetailSingle item display with markdown + metadata sidebar
FormUser input collection. Use useForm hook for validation
GridImage-heavy content (icons, thumbnails, galleries)
MenuBarExtraAlways-visible menu bar status/actions

Essential hooks (from @raycast/utils):

HookWhen to use
useFetchHTTP requests with caching
usePromiseAny async operation
useCachedPromiseAsync with stale-while-revalidate caching
useExecShell command execution
useFormForm state + validation
useLocalStoragePersistent key-value state
useCachedStateState that persists across command runs
useAIRaycast AI integration (requires Pro)
useSQLSQLite database queries

Extension rules:

  • Always set isLoading prop on top-level components during async ops
  • Use showToast(Toast.Style.Failure) for errors, not console.error
  • Use showFailureToast from @raycast/utils for standardized errors
  • First action in ActionPanel = primary (Enter key)
  • Use Action.Push for navigation, not imperative useNavigation
  • Use List.EmptyView / Grid.EmptyView for zero-state
  • Validate forms on onBlur, clear errors on onChange
  • Don't use filtering={true} when you have onSearchTextChange
  • Use environment.canAccess() before using Pro features (AI, WindowManagement)

After Generation

For script commands:

  1. Create the file in ~/Documents/raycast-scripts/
  2. Run chmod +x on the file
  3. Tell the user:
    • "Open Raycast Preferences > Extensions > + > Add Script Directory"
    • Point to ~/Documents/raycast-scripts/
    • "You only need to do this once"
  4. The command will appear in Raycast search by its @raycast.title

For extensions:

  1. Create the project in ~/Documents/raycast-scripts/<extension-name>/
  2. Run npm install in the project directory
  3. Run npm run dev to start dev mode
  4. Tell the user:
    • The extension appears at the top of Raycast search in dev mode
    • Hot reload is active (saves auto-refresh)
    • Stop dev with Ctrl+C in terminal
    • To publish: npm run publish

Icon Guidance

  • Script commands: use emoji (simplest) or 64px PNG
  • Extensions: need 512x512 PNG. Generate at https://icon.ray.so or use a placeholder
  • Support dark mode variant with [email protected] suffix
  • For extensions, always include a command-icon.png in assets/ as fallback

Categories (for extensions)

Use exactly one of: Applications, Communication, Data, Design Tools, Developer Tools, Documentation, Finance, Fun, Media, News, Other, Productivity, Security, System, Web

Common Patterns Quick Reference

Fetch + List pattern (most common extension):

import { List } from "@raycast/api";
import { useFetch } from "@raycast/utils";

export default function Command() {
  const { data, isLoading } = useFetch<Result[]>("https://api.example.com/items");
  return (
    <List isLoading={isLoading}>
      {data?.map((item) => (
        <List.Item key={item.id} title={item.name} />
      ))}
    </List>
  );
}

No-view command pattern:

import { showToast, Toast, Clipboard } from "@raycast/api";

export default async function Command() {
  const text = await Clipboard.readText();
  if (!text) {
    await showToast(Toast.Style.Failure, "Clipboard is empty");
    return;
  }
  const result = transform(text);
  await Clipboard.copy(result);
  await showToast(Toast.Style.Success, "Copied to clipboard");
}

Form + submission pattern:

import { Form, ActionPanel, Action, showToast, Toast } from "@raycast/api";
import { useForm, FormValidation } from "@raycast/utils";

interface FormValues {
  name: string;
  description: string;
}

export default function Command() {
  const { handleSubmit, itemProps } = useForm<FormValues>({
    onSubmit(values) {
      showToast(Toast.Style.Success, "Submitted", values.name);
    },
    validation: {
      name: FormValidation.Required,
    },
  });
  return (
    <Form actions={<ActionPanel><Action.SubmitForm onSubmit={handleSubmit} /></ActionPanel>}>
      <Form.TextField title="Name" placeholder="Enter name" {...itemProps.name} />
      <Form.TextArea title="Description" placeholder="Enter description" {...itemProps.description} />
    </Form>
  );
}

Script command - open URL with argument:

#!/bin/bash

# @raycast.schemaVersion 1
# @raycast.title Search Google
# @raycast.mode silent
# @raycast.icon 🔍
# @raycast.packageName Web Searches
# @raycast.argument1 { "type": "text", "placeholder": "query", "percentEncoded": true }

open "https://www.google.com/search?q=$1"

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.