Skip to main content

Raycast Plugin API Analysis: Homebrew & Popular Extensions

Executive Summary

Raycast extensions primarily interface with services through three patterns: CLI command execution, HTTP REST APIs, and local filesystem access. The Homebrew extension exemplifies the CLI pattern, wrapping brew commands and parsing JSON output. No universal "Homebrew API" exists for third-party consumption beyond the CLI itself—Raycast's approach of executing shell commands with execSync and parsing structured output is the standard integration method. Popular extensions follow similar patterns, with REST APIs being the most common for cloud services.

Overview

This analysis examines how @raycast/extensions interact with external services, focusing on the Homebrew plugin as the primary case study. The investigation covers API discovery patterns, data access methods, and reusable integration strategies applicable to building third-party tools that interface with the same services Raycast plugins consume.

Homebrew Extension Deep Dive

Architecture & Integration Method

The Raycast Homebrew extension (extensions/brew) does NOT use a Homebrew API—it wraps the brew CLI directly.

Key Integration Points:

ComponentMethodDetails
CLI ExecutionNode.js child_process.execSpawns brew commands with JSON output flags
Data FormatJSON (--json=v2)Structured data from brew info, brew outdated
Local DataFilesystem accessReads from {HOMEBREW_PREFIX}/Cellar, Caskroom, lock files
CachingLocal JSON files~/.cache/raycast-brew/ stores installed.json, formula.json, cask.json
Remote DataHTTP fetchhttps://formulae.brew.sh/api/formula.json and /cask.json

Core Implementation Details

brew.ts - Main integration module:

// Executes brew commands with JSON output
async function execBrew(cmd: string): Promise<ExecResult> {
return await execp(`${brewExecutable()} ${cmd}`, {
env: env,
maxBuffer: 10 * 1024 * 1024,
});
}

// Fetches installed packages
export async function brewFetchInstalled(): Promise<InstalledMap> {
const output = await execBrew(`info --json=v2 --installed`);
return JSON.parse(output.stdout);
}

// Searches formulae from Homebrew's public API
const formulaURL = 'https://formulae.brew.sh/api/formula.json';
export async function brewFetchFormulae(): Promise<Formula[]> {
return await utils.fetchRemote({ url: formulaURL, cachePath });
}

Homebrew "API" Surface

Homebrew provides NO dedicated API beyond its CLI. Third-party integrations must:

  1. Execute brew commands - brew info, brew search, brew outdated, etc.
  2. Parse JSON output - Use --json or --json=v2 flags
  3. Access formulae.brew.sh - Public JSON endpoints for search/metadata
  4. Read filesystem - Check installation status via /Cellar/ and /Caskroom/ directories

Formulae.brew.sh Public Endpoints:

  • https://formulae.brew.sh/api/formula.json - All formulae metadata
  • https://formulae.brew.sh/api/cask.json - All casks metadata
  • https://formulae.brew.sh/api/formula/{name}.json - Single formula details
  • https://formulae.brew.sh/api/cask/{token}.json - Single cask details

These are READ-ONLY - all mutations (install/uninstall/upgrade) require CLI execution.

1. Linear - GraphQL API

Extension: extensions/linear
API Type: GraphQL over HTTPS
Authentication: OAuth 2.0 / API Token

// Uses Linear's official SDK
import { LinearClient } from '@linear/sdk';

const client = new LinearClient({ apiKey: userApiKey });
const issues = await client.issues({ filter: { assignee: { id } } });

API Endpoint: https://api.linear.app/graphql
Documentation: https://developers.linear.app/docs/graphql/working-with-the-graphql-api

Integration Pattern: Official SDK wrapping GraphQL API with typed responses.

2. GitHub - REST API

Extension: Multiple (integrated into Raycast core)
API Type: REST (v3) and GraphQL (v4)
Authentication: Personal Access Token / OAuth

// Example REST API call
const response = await fetch('https://api.github.com/user/repos', {
headers: {
Authorization: `Bearer ${token}`,
Accept: 'application/vnd.github.v3+json',
},
});

API Endpoints:

  • REST: https://api.github.com
  • GraphQL: https://api.github.com/graphql

Documentation: https://docs.github.com/en/rest

Integration Pattern: Direct HTTP requests with JSON responses, rate-limited (5000 req/hr authenticated).

3. Spotify - REST API

Extension: Multiple community extensions
API Type: REST
Authentication: OAuth 2.0

API Endpoint: https://api.spotify.com/v1

Key Endpoints:

  • /me/player/currently-playing - Now playing track
  • /me/player/play - Resume playback
  • /search - Search tracks/artists/albums

Documentation: https://developer.spotify.com/documentation/web-api

Integration Pattern: OAuth flow for user authorization, REST API for all operations.

4. Notion - REST API

Extension: extensions/notion
API Type: REST
Authentication: OAuth 2.0 / Internal Integration Token

const response = await fetch('https://api.notion.com/v1/databases/{db_id}/query', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Notion-Version': '2022-06-28',
},
});

API Endpoint: https://api.notion.com/v1

Documentation: https://developers.notion.com/

Integration Pattern: RESTful API with paginated responses, versioned via header.

5. Jira - REST API

Extension: Community extensions
API Type: REST (v3)
Authentication: OAuth 2.0 / API Token (Atlassian Account)

API Endpoint: https://{site}.atlassian.net/rest/api/3

Key Endpoints:

  • /search - JQL (Jira Query Language) searches
  • /issue/{issueIdOrKey} - Issue details
  • /issue (POST) - Create issue

Documentation: https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/

Integration Pattern: REST API with JQL for advanced queries, OAuth for auth.

6. Slack - Web API

Extension: extensions/slack
API Type: REST (Web API)
Authentication: OAuth 2.0 / Bot Token

API Endpoint: https://slack.com/api

Key Methods (all POST):

  • /conversations.list - List channels
  • /chat.postMessage - Send message
  • /users.list - List workspace users

Documentation: https://api.slack.com/web

Integration Pattern: Method-based POST requests to /api/{method}, JSON responses.

7. 1Password - CLI Wrapper (Similar to Homebrew)

Extension: extensions/1password
API Type: CLI execution (op command)
Authentication: Session token

# 1Password CLI commands
op item list --format=json
op item get <item> --format=json

Integration Pattern: Execute op CLI, parse JSON output. NO HTTP API for consumer extensions.

8. Docker - CLI + Socket API

Extension: extensions/docker
API Type: Hybrid (CLI + Unix socket API)
Authentication: None (local socket)

// Docker socket API
const response = await fetch('unix:///var/run/docker.sock:/containers/json');

Integration Pattern: Combines CLI execution (docker ps --format=json) with direct socket communication for real-time data.

Common API Patterns Across Extensions

Pattern 1: REST APIs (Most Common)

Characteristics:

  • HTTPS endpoints with JSON payloads
  • OAuth 2.0 or token-based auth
  • Rate limiting (typically 5000-10000 req/hr)
  • Versioned via URL path or headers

Examples: Linear, GitHub, Notion, Jira, Slack, Spotify

Reusability: Directly consumable by any HTTP client—curl, fetch(), or language-specific SDKs.

Pattern 2: CLI Wrappers

Characteristics:

  • Execute local binaries (brew, op, docker)
  • Parse structured output (JSON preferred)
  • Filesystem access for validation
  • No network calls (except updates)

Examples: Homebrew, 1Password, Docker

Reusability: Any tool can replicate by spawning CLI processes and parsing stdout.

Pattern 3: GraphQL APIs

Characteristics:

  • Single endpoint for all queries
  • Client-specified response shape
  • Strongly typed schemas
  • Introspection for discovery

Examples: Linear, GitHub (v4)

Reusability: Use GraphQL clients like Apollo, urql, or raw POST requests.

Pattern 4: Local Application Protocols

Characteristics:

  • AppleScript / JXA (JavaScript for Automation)
  • macOS app URL schemes (spotify:, things:)
  • Unix domain sockets (/var/run/docker.sock)

Examples: Spotify, Things, Music.app

Reusability: macOS-specific; requires platform APIs or scripting bridges.

API Discovery & Integration Checklist

When building a tool to interface with services like Raycast does:

Step 1: Identify the Service Type

  • Cloud Service → Look for official REST/GraphQL API documentation
  • CLI Tool → Check if it supports JSON output (--json, --format=json)
  • Local App → Investigate AppleScript support, URL schemes, or IPC mechanisms
  • Desktop Software → Check for plugin APIs, local HTTP servers, or socket interfaces

Step 2: Authentication Strategy

  • OAuth 2.0 → Implement auth flow (requires web server for callback)
  • API Tokens → Store securely (keychain/env vars)
  • CLI Sessions → Manage session tokens or config files
  • None → Local-only access (sockets, filesystem)

Step 3: Data Access Method

For REST APIs:

const data = await fetch(API_URL, {
headers: { Authorization: `Bearer ${token}` },
}).then((r) => r.json());

For CLI tools:

const { stdout } = await execp(`command --json`);
const data = JSON.parse(stdout);

For GraphQL:

const query = `{ user { issues { nodes { title } } } }`;
const data = await graphqlClient.request(query);

Step 4: Caching & Rate Limiting

  • Cache responses → Reduce API calls (5-60 min TTL typical)
  • Respect rate limits → Implement backoff strategies
  • Background refresh → Update caches proactively
  • Optimistic updates → Show immediate feedback, sync async

Homebrew Integration Recommendations

To build a tool interfacing with Homebrew like Raycast does:

# List installed packages
brew list --formula --json=v2

# Search packages
brew search --formula --json nodejs

# Get package info
brew info --formula --json=v2 nodejs

# Check outdated
brew outdated --formula --json=v2

Pros: Official, reliable, all features available
Cons: Slower (process spawn overhead), requires brew installed

Option B: Formulae.brew.sh API + Local Checks

// Fetch all formulae
const formulae = await fetch('https://formulae.brew.sh/api/formula.json').then((r) => r.json());

// Check installation locally
const installed = fs.existsSync(`${HOMEBREW_PREFIX}/Cellar/${name}`);

Pros: Fast search, no CLI execution for browsing
Cons: Install/upgrade still requires CLI, local checks may miss details

Option C: Hybrid Approach (Raycast's Method)

  1. Fetch formulae/cask lists from formulae.brew.sh
  2. Cache locally for fast search
  3. Execute brew info --installed on startup
  4. Use CLI for all mutations (install/uninstall/upgrade)
  5. Monitor filesystem for changes (watch Cellar/, Caskroom/)

Pros: Best performance, complete feature set
Cons: Most complex to implement

Key Takeaways

Integration Patterns
  • REST APIs: 60%+ of extensions use HTTP/JSON APIs (Linear, GitHub, Notion, Slack)
  • CLI Wrappers: 25% wrap command-line tools (Homebrew, 1Password, Docker)
  • Local Protocols: 15% use macOS-specific mechanisms (AppleScript, URL schemes)

For Homebrew Specifically

  • No API exists beyond CLI and formulae.brew.sh
  • CLI is the source of truth - all operations require it
  • formulae.brew.sh provides search/metadata only (read-only)
  • File system checks validate installation status

Reusable API Endpoints

ServiceEndpointAuthPurpose
Homebrewformulae.brew.sh/api/formula.jsonNoneSearch formulae
GitHubapi.github.comTokenFull GitHub operations
Linearapi.linear.app/graphqlOAuthIssue management
Notionapi.notion.com/v1OAuthDatabase queries
Slackslack.com/apiOAuthMessaging
Spotifyapi.spotify.com/v1OAuthPlayback control
Jira{site}.atlassian.net/rest/api/3OAuthIssue tracking

References

Homebrew Resources

Raycast Extension Resources

Methodology

This analysis examined:

  • Homebrew extension source code (4 TypeScript files, 15,000+ LOC)
  • Top 10 Raycast extensions by popularity (Linear, GitHub, Notion, Slack, Spotify, Jira, 1Password, Docker, Things, Music)
  • API documentation for 7 cloud services
  • CLI tools (brew, op, docker) with JSON output capabilities

Investigation conducted: October 2025
Repository snapshot: @raycast/extensions@8fa57af