Raycast — macOS Launcher Extension Development

## Overview

25 stars

Best use case

Raycast — macOS Launcher Extension Development is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

## Overview

Teams using Raycast — macOS Launcher Extension Development should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/raycast/SKILL.md --create-dirs "https://raw.githubusercontent.com/ComeOnOliver/skillshub/main/skills/TerminalSkills/skills/raycast/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/raycast/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How Raycast — macOS Launcher Extension Development Compares

Feature / AgentRaycast — macOS Launcher Extension DevelopmentStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

## Overview

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Raycast — macOS Launcher Extension Development


## Overview


Building Raycast extensions — custom commands, views, and integrations for the Raycast launcher on macOS. Helps developers create productivity extensions using React, TypeScript, and Raycast's API for lists, forms, actions, and preferences.


## Instructions

### List View Command

Build a searchable list command:

```tsx
// src/search-projects.tsx — Search and open projects from a list
import { List, Action, ActionPanel, Icon, Color, getPreferenceValues } from "@raycast/api";
import { useFetch } from "@raycast/utils";

interface Project {
  id: string;
  name: string;
  url: string;
  language: string;
  stars: number;
  updatedAt: string;
}

export default function SearchProjects() {
  const prefs = getPreferenceValues<{ githubToken: string }>();

  const { data, isLoading } = useFetch<{ items: Project[] }>(
    "https://api.github.com/user/repos?sort=updated&per_page=50",
    {
      headers: { Authorization: `Bearer ${prefs.githubToken}` },
      mapResult: (result: any) => ({
        data: { items: result },
      }),
    }
  );

  return (
    <List isLoading={isLoading} searchBarPlaceholder="Search your repos...">
      {data?.items.map((project) => (
        <List.Item
          key={project.id}
          title={project.name}
          subtitle={project.language}
          accessories={[
            { text: `⭐ ${project.stars}` },
            { date: new Date(project.updatedAt), tooltip: "Last updated" },
          ]}
          icon={{ source: Icon.Code, tintColor: Color.Blue }}
          actions={
            <ActionPanel>
              <Action.OpenInBrowser url={project.url} title="Open on GitHub" />
              <Action.CopyToClipboard
                content={`git clone ${project.url}.git`}
                title="Copy Clone URL"
              />
              <Action.Open
                title="Open in VS Code"
                target={project.url}
                application="Visual Studio Code"
              />
            </ActionPanel>
          }
        />
      ))}
    </List>
  );
}
```

### Detail View

Show rich content with markdown:

```tsx
// src/show-readme.tsx — Display a project README with rich formatting
import { Detail, Action, ActionPanel } from "@raycast/api";
import { useFetch } from "@raycast/utils";

export default function ShowReadme({ repoName }: { repoName: string }) {
  const { data, isLoading } = useFetch<string>(
    `https://api.github.com/repos/${repoName}/readme`,
    {
      headers: { Accept: "application/vnd.github.raw" },
      mapResult: (result: any) => ({ data: result }),
    }
  );

  const markdown = data ?? "Loading...";

  return (
    <Detail
      isLoading={isLoading}
      markdown={markdown}
      metadata={
        <Detail.Metadata>
          <Detail.Metadata.Label title="Repository" text={repoName} />
          <Detail.Metadata.Link title="GitHub" target={`https://github.com/${repoName}`} text="Open" />
          <Detail.Metadata.Separator />
          <Detail.Metadata.TagList title="Topics">
            <Detail.Metadata.TagList.Item text="typescript" color={Color.Blue} />
            <Detail.Metadata.TagList.Item text="react" color={Color.Green} />
          </Detail.Metadata.TagList>
        </Detail.Metadata>
      }
      actions={
        <ActionPanel>
          <Action.CopyToClipboard content={markdown} title="Copy README" />
        </ActionPanel>
      }
    />
  );
}
```

### Form Command

Collect user input with forms:

```tsx
// src/create-issue.tsx — Form to create a GitHub issue
import { Form, Action, ActionPanel, showToast, Toast, popToRoot } from "@raycast/api";
import { useState } from "react";

export default function CreateIssue() {
  const [isSubmitting, setIsSubmitting] = useState(false);

  async function handleSubmit(values: {
    repo: string;
    title: string;
    body: string;
    labels: string[];
    priority: string;
  }) {
    setIsSubmitting(true);

    try {
      const response = await fetch(`https://api.github.com/repos/${values.repo}/issues`, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${getPreferenceValues().githubToken}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          title: values.title,
          body: values.body,
          labels: values.labels,
        }),
      });

      if (!response.ok) throw new Error("Failed to create issue");

      const issue = await response.json();
      await showToast({
        style: Toast.Style.Success,
        title: "Issue Created",
        message: `#${issue.number}: ${issue.title}`,
        primaryAction: {
          title: "Open in Browser",
          onAction: () => open(issue.html_url),
        },
      });
      popToRoot();
    } catch (error) {
      await showToast({ style: Toast.Style.Failure, title: "Error", message: String(error) });
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    <Form
      isLoading={isSubmitting}
      actions={
        <ActionPanel>
          <Action.SubmitForm title="Create Issue" onSubmit={handleSubmit} />
        </ActionPanel>
      }
    >
      <Form.TextField id="repo" title="Repository" placeholder="owner/repo" />
      <Form.TextField id="title" title="Title" placeholder="Bug: ..." />
      <Form.TextArea id="body" title="Description" placeholder="Describe the issue..." enableMarkdown />
      <Form.TagPicker id="labels" title="Labels">
        <Form.TagPicker.Item value="bug" title="🐛 Bug" />
        <Form.TagPicker.Item value="feature" title="✨ Feature" />
        <Form.TagPicker.Item value="docs" title="📝 Docs" />
      </Form.TagPicker>
      <Form.Dropdown id="priority" title="Priority" defaultValue="medium">
        <Form.Dropdown.Item value="low" title="Low" />
        <Form.Dropdown.Item value="medium" title="Medium" />
        <Form.Dropdown.Item value="high" title="High" />
        <Form.Dropdown.Item value="critical" title="Critical" />
      </Form.Dropdown>
    </Form>
  );
}
```

### Local Storage and Cache

Persist data across command runs:

```typescript
// src/lib/storage.ts — Cache and persist data
import { LocalStorage, Cache } from "@raycast/api";

const cache = new Cache();

// Cache for frequently accessed data (memory + disk, auto-evicts)
async function getCachedRepos(): Promise<Project[]> {
  const cached = cache.get("repos");
  if (cached) return JSON.parse(cached);

  const repos = await fetchRepos();
  cache.set("repos", JSON.stringify(repos), { ttl: 300_000 }); // 5-minute TTL
  return repos;
}

// LocalStorage for persistent user data (survives restarts)
async function addToFavorites(repoId: string) {
  const favorites = JSON.parse((await LocalStorage.getItem<string>("favorites")) ?? "[]");
  if (!favorites.includes(repoId)) {
    favorites.push(repoId);
    await LocalStorage.setItem("favorites", JSON.stringify(favorites));
  }
}

async function getFavorites(): Promise<string[]> {
  return JSON.parse((await LocalStorage.getItem<string>("favorites")) ?? "[]");
}
```

### Menu Bar Command

Create a persistent menu bar item:

```tsx
// src/menu-bar.tsx — Always-visible status in the macOS menu bar
import { MenuBarExtra, Icon, open, getPreferenceValues } from "@raycast/api";
import { useFetch } from "@raycast/utils";

export default function StatusMenuBar() {
  const { data, isLoading } = useFetch<any[]>(
    "https://api.github.com/notifications",
    {
      headers: { Authorization: `Bearer ${getPreferenceValues().githubToken}` },
      keepPreviousData: true,
      initialData: [],
    }
  );

  const unread = data?.length ?? 0;

  return (
    <MenuBarExtra
      icon={Icon.Bell}
      title={unread > 0 ? String(unread) : undefined}
      isLoading={isLoading}
    >
      <MenuBarExtra.Section title="Notifications">
        {data?.slice(0, 10).map((notification) => (
          <MenuBarExtra.Item
            key={notification.id}
            title={notification.subject.title}
            subtitle={notification.repository.name}
            onAction={() => open(notification.subject.url)}
          />
        ))}
      </MenuBarExtra.Section>
      {unread > 10 && (
        <MenuBarExtra.Item
          title={`${unread - 10} more...`}
          onAction={() => open("https://github.com/notifications")}
        />
      )}
    </MenuBarExtra>
  );
}
```

### Extension Manifest

Configure commands and preferences:

```json
// package.json — Extension configuration
{
  "name": "my-github-extension",
  "title": "GitHub Tools",
  "description": "Manage GitHub repos, issues, and notifications",
  "icon": "github-icon.png",
  "author": "your-name",
  "categories": ["Developer Tools"],
  "license": "MIT",
  "commands": [
    {
      "name": "search-projects",
      "title": "Search Projects",
      "description": "Search and open your GitHub repositories",
      "mode": "view"
    },
    {
      "name": "create-issue",
      "title": "Create Issue",
      "description": "Create a new GitHub issue",
      "mode": "view"
    },
    {
      "name": "menu-bar",
      "title": "GitHub Notifications",
      "description": "Show unread notifications in menu bar",
      "mode": "menu-bar",
      "interval": "5m"
    }
  ],
  "preferences": [
    {
      "name": "githubToken",
      "title": "GitHub Token",
      "description": "Personal access token with repo scope",
      "type": "password",
      "required": true
    }
  ]
}
```

## Installation

```bash
# Create a new extension
npx create-raycast-extension my-extension

# Development (opens Raycast with hot reload)
npm run dev

# Build and lint
npm run build
npm run fix-lint

# Publish to Raycast Store
npx ray publish
```


## Examples


### Example 1: Setting up Raycast with a custom configuration

**User request:**

```
I just installed Raycast. Help me configure it for my TypeScript + React workflow with my preferred keybindings.
```

The agent creates the configuration file with TypeScript-aware settings, configures relevant plugins/extensions for React development, sets up keyboard shortcuts matching the user's preferences, and verifies the setup works correctly.

### Example 2: Extending Raycast with custom functionality

**User request:**

```
I want to add a custom detail view to Raycast. How do I build one?
```

The agent scaffolds the extension/plugin project, implements the core functionality following Raycast's API patterns, adds configuration options, and provides testing instructions to verify it works end-to-end.


## Guidelines

1. **Fast time-to-interaction** — Show cached data immediately, then update in background; use `keepPreviousData: true`
2. **Use useFetch from @raycast/utils** — Handles caching, revalidation, and loading states automatically
3. **Meaningful accessories** — Show dates, counts, and status in list item accessories; saves users from opening details
4. **Action panel hierarchy** — Most common action first; Cmd+Enter triggers the primary action
5. **Preferences for secrets** — API keys and tokens go in preferences (type: "password"), not hardcoded
6. **Show toasts for feedback** — Success/failure toasts keep users informed without blocking the UI
7. **Menu bar for monitoring** — Use menu bar commands for status that users check frequently (notifications, CI status)
8. **Cache aggressively** — Raycast commands should feel instant; cache API responses and pre-fetch data

Related Skills

managing-autonomous-development

25
from ComeOnOliver/skillshub

Enables Claude to manage Sugar's autonomous development workflows. It allows Claude to create tasks, view the status of the system, review pending tasks, and start autonomous execution mode. Use this skill when the user asks to create a new development task using `/sugar-task`, check the system status with `/sugar-status`, review pending tasks via `/sugar-review`, or initiate autonomous development using `/sugar-run`. It provides a comprehensive interface for interacting with the Sugar autonomous development system.

overnight-development

25
from ComeOnOliver/skillshub

Automates software development overnight using git hooks to enforce test-driven Use when appropriate context detected. Trigger with relevant phrases based on skill purpose.

cursor-extension-integration

25
from ComeOnOliver/skillshub

Integrate VS Code extensions with Cursor IDE: compatibility, Open VSX registry, VSIX installation, conflict resolution, and essential extensions. Triggers on "cursor extensions", "cursor vscode extensions", "cursor plugins", "cursor marketplace", "open vsx", "vsix install".

defold-native-extension-editing

25
from ComeOnOliver/skillshub

Defold native extension development. Use when creating or editing C/C++ (.c, .cpp, .h, .hpp), JavaScript (.js), or manifest files in native extension directories (src/, include/, lib/, api/).

macos-cleaner

25
from ComeOnOliver/skillshub

Analyze and reclaim macOS disk space through intelligent cleanup recommendations. This skill should be used when users report disk space issues, need to clean up their Mac, or want to understand what's consuming storage. Focus on safe, interactive analysis with user confirmation before any deletions.

ros2-development

25
from ComeOnOliver/skillshub

Comprehensive best practices, design patterns, and common pitfalls for ROS2 (Robot Operating System 2) development. Use this skill when building ROS2 nodes, packages, launch files, components, or debugging ROS2 systems. Trigger whenever the user mentions ROS2, colcon, rclpy, rclcpp, DDS, QoS, lifecycle nodes, managed nodes, ROS2 launch, ROS2 parameters, ROS2 actions, nav2, MoveIt2, micro-ROS, or any ROS2-era robotics middleware. Also trigger for ROS2 workspace setup, DDS tuning, intra-process communication, ROS2 security, or deploying ROS2 in production. Also trigger for colcon build issues, ament_cmake, ament_python, CMakeLists.txt for ROS2, package.xml dependencies, rosdep, workspace overlays, custom message generation, or ROS2 build troubleshooting. Covers Humble, Iron, Jazzy, and Rolling distributions.

ros1-development

25
from ComeOnOliver/skillshub

Best practices, design patterns, and common pitfalls for ROS1 (Robot Operating System 1) development. Use this skill when building ROS1 nodes, packages, launch files, or debugging ROS1 systems. Trigger whenever the user mentions ROS1, catkin, rospy, roscpp, roslaunch, roscore, rostopic, tf, actionlib, message types, services, or any ROS1-era robotics middleware. Also trigger for migrating ROS1 code to ROS2, maintaining legacy ROS1 systems, or building ROS1-ROS2 bridges. Covers catkin workspaces, nodelets, dynamic reconfigure, pluginlib, and the full ROS1 ecosystem.

docker-ros2-development

25
from ComeOnOliver/skillshub

Best practices for Docker-based ROS2 development including multi-stage Dockerfiles, docker-compose for multi-container robotic systems, DDS discovery across containers, GPU passthrough for perception, and dev-vs-deploy container patterns. Use this skill when containerizing ROS2 workspaces, setting up docker-compose for robot software stacks, debugging DDS communication between containers, configuring NVIDIA Container Toolkit for GPU workloads, forwarding X11/Wayland for rviz2 and GUI tools, or managing USB device passthrough for cameras and serial devices. Trigger whenever the user mentions Docker with ROS2, docker-compose for robots, Dockerfile for colcon workspaces, container networking for DDS, GPU containers for perception, devcontainer for ROS2, multi-stage builds for ROS2, or deploying ROS2 in containers. Also trigger for CI/CD with Docker-based ROS2 builds, CycloneDDS or FastDDS configuration in containers, shared memory in Docker, or X11 forwarding for rviz2. Covers Humble, Iron, Jazzy, and Rolling distributions across Ubuntu 22.04 and 24.04 base images.

apify-actor-development

25
from ComeOnOliver/skillshub

Develop, debug, and deploy Apify Actors - serverless cloud programs for web scraping, automation, and data processing. Use when creating new Actors, modifying existing ones, or troubleshooting Actor code.

docker-development

25
from ComeOnOliver/skillshub

Docker and container development agent skill and plugin for Dockerfile optimization, docker-compose orchestration, multi-stage builds, and container security hardening. Use when: user wants to optimize a Dockerfile, create or improve docker-compose configurations, implement multi-stage builds, audit container security, reduce image size, or follow container best practices. Covers build performance, layer caching, secret management, and production-ready container patterns.

browser-extension-developer

25
from ComeOnOliver/skillshub

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

vue-development-guides

25
from ComeOnOliver/skillshub

A collection of best practices and tips for developing applications using Vue.js. This skill MUST be apply when developing, refactoring or reviewing Vue.js or Nuxt projects.