Skip to main content

Overview

SuperCmd provides a comprehensive compatibility layer that implements the entire Raycast API surface. This allows existing Raycast extensions to run without modification while enabling SuperCmd-specific enhancements.
The API shim lives in src/renderer/src/raycast-api/ and is split into focused runtime modules for maintainability. The index.tsx file serves as the integration surface that wires everything together.

Architecture

The Raycast API implementation follows a modular architecture:
raycast-api/
β”œβ”€β”€ index.tsx                  # Main export surface
β”œβ”€β”€ action-runtime*.tsx        # Action & ActionPanel
β”œβ”€β”€ list-runtime*.tsx          # List component
β”œβ”€β”€ form-runtime*.tsx          # Form component
β”œβ”€β”€ grid-runtime*.tsx          # Grid component
β”œβ”€β”€ detail-runtime.tsx         # Detail component
β”œβ”€β”€ menubar-runtime*.tsx       # MenuBarExtra
β”œβ”€β”€ icon-runtime*.tsx          # Icon system
β”œβ”€β”€ hooks/                     # @raycast/utils hooks
└── oauth/                     # OAuth implementation

Core Exports

Components

All major Raycast components are fully implemented:
import { List } from '@raycast/api';

export default function Command() {
  return (
    <List>
      <List.Item
        title="Item 1"
        accessories={[
          { text: 'Badge' },
          { icon: Icon.Star }
        ]}
        actions={
          <ActionPanel>
            <Action.OpenInBrowser url="https://example.com" />
          </ActionPanel>
        }
      />
    </List>
  );
}
Features:
  • Filtering with onSearchTextChange
  • Pagination support
  • Accessories (text, icons, dates)
  • List.Item.Detail with Metadata
  • Sections with subtitles
  • Empty states

Hooks

The useNavigation hook provides navigation stack control:
import { useNavigation } from '@raycast/api';

function MyComponent() {
  const { push, pop } = useNavigation();
  
  return (
    <Action
      title="Go to Details"
      onAction={() => push(<DetailView />)}
    />
  );
}

Functions

Window Management

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

await showToast({
  style: Toast.Style.Success,
  title: 'Operation Complete',
  message: 'Your data has been saved',
  primaryAction: {
    title: 'Undo',
    onAction: () => console.log('Undo'),
  },
});
Toast Styles:
  • Toast.Style.Success - Green checkmark
  • Toast.Style.Failure - Red error
  • Toast.Style.Animated - Loading spinner

System Integration

import {
  getApplications,
  getDefaultApplication,
  getFrontmostApplication,
  open,
} from '@raycast/api';

// Get all installed applications
const apps = await getApplications();

// Get default app for a file
const defaultApp = await getDefaultApplication('document.pdf');

// Get currently active app
const frontmost = await getFrontmostApplication();

// Open URL in default browser
await open('https://example.com');

// Open URL in specific app
await open('https://example.com', 'Safari');
import {
  getSelectedFinderItems,
  showInFinder,
  trash,
} from '@raycast/api';

// Get selected files in Finder
const files = await getSelectedFinderItems();

// Show file in Finder
await showInFinder('/path/to/file.txt');

// Move to trash
await trash(['/path/to/file.txt']);

Storage & State

LocalStorage

Persistent key-value storage scoped to each extension:
import { LocalStorage } from '@raycast/api';

// Store values (supports string, number, boolean)
await LocalStorage.setItem('lastSearch', 'raycast');
await LocalStorage.setItem('count', 42);
await LocalStorage.setItem('enabled', true);

// Retrieve values
const search = await LocalStorage.getItem('lastSearch'); // 'raycast'
const count = await LocalStorage.getItem('count');       // 42

// Get all items
const all = await LocalStorage.allItems();

// Remove items
await LocalStorage.removeItem('lastSearch');
await LocalStorage.clear();
SuperCmd uses a scoped prefix (sc-ext:{extensionName}:) to isolate storage between extensions. Legacy keys are automatically migrated.

Cache

LRU cache with size limits:
import { Cache } from '@raycast/api';

const cache = new Cache({
  capacity: 10 * 1024 * 1024, // 10MB
  namespace: 'my-cache',
});

// Store data
cache.set('user:123', JSON.stringify(userData));

// Retrieve data
const cached = cache.get('user:123');

// Subscribe to changes
const unsubscribe = cache.subscribe((key, data) => {
  console.log(`Cache updated: ${key}`);
});

Clipboard

Advanced clipboard operations with history support:
import { Clipboard } from '@raycast/api';

// Copy text
await Clipboard.copy('Hello World');

// Copy without showing toast
await Clipboard.copy('Secret', { concealed: true });

// Copy rich content
await Clipboard.copy({
  text: 'Plain text',
  html: '<b>Rich HTML</b>',
});

// Copy files
await Clipboard.copy({
  file: '/path/to/image.png',
});

// Read clipboard
const text = await Clipboard.readText();
const content = await Clipboard.read(); // { text, html, file }

// Paste to active app
await Clipboard.paste('Text to paste');

AI Integration

Full AI API with streaming support:
import { AI } from '@raycast/api';

const answer = await AI.ask('What is the capital of France?', {
  model: AI.Model.Anthropic_Claude_Sonnet,
  creativity: 'medium',
});

console.log(answer); // 'Paris'

@raycast/utils Hooks

Advanced utility hooks for common patterns:
import { useCachedPromise } from '@raycast/utils';

function SearchCommand() {
  const { data, isLoading, revalidate } = useCachedPromise(
    async (query: string) => {
      const response = await fetch(`/api/search?q=${query}`);
      return response.json();
    },
    ['initial query'],
    {
      keepPreviousData: true,
    }
  );
  
  return (
    <List isLoading={isLoading}>
      {data?.map(item => (
        <List.Item key={item.id} title={item.title} />
      ))}
    </List>
  );
}

Icon System

SuperCmd maps Raycast icon names to Phosphor icons:
import { Icon, Color, List } from '@raycast/api';

<List.Item
  icon={{ source: Icon.Star, tintColor: Color.Yellow }}
  title="Favorite"
/>

<List.Item
  icon={{ source: 'custom-icon.png' }}  // Asset from extension
  title="Custom Icon"
/>

<List.Item
  icon="πŸŽ‰"  // Emoji
  title="Celebration"
/>

Icon Runtime

The icon system is split into focused modules:

icon-runtime-phosphor.tsx

Raycast icon name β†’ Phosphor icon mapping with 200+ icons

icon-runtime-assets.tsx

Asset path normalization and sc-asset:// protocol handling

icon-runtime-render.tsx

Actual rendering logic with tint color support

icon-runtime-config.ts

Extension context injection for asset resolution

Environment Object

Provides extension context and system information:
import { environment, LaunchType } from '@raycast/api';

environment.extensionName;      // 'my-extension'
environment.commandName;        // 'search'
environment.commandMode;        // 'view' | 'no-view' | 'menu-bar'
environment.assetsPath;         // '/path/to/assets'
environment.supportPath;        // '/path/to/extension/data'
environment.raycastVersion;     // '1.80.0'
environment.appearance;         // 'dark' | 'light'
environment.launchType;         // LaunchType.UserInitiated
environment.isDevelopment;      // false

// Feature detection
if (environment.canAccess(AI)) {
  // AI is available
}

OAuth Implementation

Full OAuth 2.0 support with PKCE:
import { OAuth } from '@raycast/api';

const client = new OAuth.PKCEClient({
  redirectMethod: OAuth.RedirectMethod.Web,
  providerName: 'GitHub',
  providerIcon: 'github-logo.png',
  description: 'Connect your GitHub account',
});

const authRequest = await client.authorizationRequest({
  endpoint: 'https://github.com/login/oauth/authorize',
  clientId: 'your-client-id',
  scope: 'repo user',
});

const { authorizationCode } = await client.authorize(authRequest);

const tokens = await client.exchangeTokens({
  endpoint: 'https://github.com/login/oauth/access_token',
  clientId: 'your-client-id',
  codeVerifier: authRequest.codeVerifier,
  authorizationCode,
});

await client.setTokens(tokens);

OAuth Service Presets

Pre-configured services for popular providers:
import { OAuthService } from '@raycast/api';

const github = OAuthService.github({
  clientId: 'your-client-id',
  scope: 'repo user',
});

const spotify = OAuthService.spotify({
  clientId: 'your-client-id',
  scope: 'user-read-private',
});

const linear = OAuthService.linear({
  clientId: 'your-client-id',
  scope: 'read write',
});

Implementation Status

SuperCmd implements 100% of the core Raycast API:
  • βœ… List (with filtering, pagination, accessories, Detail)
  • βœ… Detail (with Metadata: Label, Link, TagList, Separator)
  • βœ… Form (all field types, validation, drafts)
  • βœ… Grid (sections, fit modes, aspect ratio)
  • βœ… ActionPanel (with Submenu)
  • βœ… Action (all action types)
  • βœ… MenuBarExtra (menu bar integration)
  • βœ… showToast, showHUD, confirmAlert
  • βœ… open, closeMainWindow, popToRoot
  • βœ… launchCommand, clearSearchBar
  • βœ… getApplications, getDefaultApplication, getFrontmostApplication
  • βœ… getSelectedText, getSelectedFinderItems
  • βœ… trash, showInFinder
  • βœ… openExtensionPreferences, openCommandPreferences
  • βœ… updateCommandMetadata
  • βœ… captureException
  • βœ… useFetch (with pagination)
  • βœ… useCachedPromise (with cursor pagination)
  • βœ… useCachedState
  • βœ… usePromise (with mutate/revalidate)
  • βœ… useForm (with validation)
  • βœ… useExec
  • βœ… useSQL
  • βœ… useStreamJSON
  • βœ… useAI
  • βœ… useFrecencySorting
  • βœ… useLocalStorage

Best Practices

  • Always import from @raycast/api, never from internal paths
  • Use TypeScript for better type safety and autocomplete
  • Handle loading and error states in async operations
  • Test extensions with different themes (dark/light)
  • Use useCachedPromise for expensive async operations
  • Leverage keepPreviousData to prevent loading flickers
  • Avoid heavy computation in render functions
  • Use React.memo() for frequently re-rendered components
  • Always wrap async operations in try/catch
  • Show user-friendly error messages with showToast
  • Use captureException() to log errors
  • Provide fallback UI for error states

See Also

Extension Runtime

Learn how extensions are loaded and executed

Electron Architecture

Understand the IPC bridge and process model

Raycast API Docs

Official Raycast API documentation

Build docs developers (and LLMs) love